165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/* 265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project 365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License"); 565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License. 665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at 765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * http://www.apache.org/licenses/LICENSE-2.0 965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software 1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS, 1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and 1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License. 1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.device.display.daydream; 1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.R; 2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.Action; 2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.ComponentName; 2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Context; 2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Intent; 2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.pm.PackageManager; 2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.pm.ResolveInfo; 2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.pm.PackageManager.NameNotFoundException; 2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.Resources; 2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.TypedArray; 3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.XmlResourceParser; 3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.drawable.Drawable; 3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Parcel; 3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Parcelable; 3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.service.dreams.DreamService; 3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.AttributeSet; 3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Log; 3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Xml; 3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport org.xmlpull.v1.XmlPullParser; 4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport org.xmlpull.v1.XmlPullParserException; 4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.io.IOException; 4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.Comparator; 4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic class DreamInfoAction extends Action { 4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int CHECK_SET_ID = 1; 4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane static class DreamInfoActionComparator implements Comparator<DreamInfoAction> { 5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final ComponentName mDefaultDream; 5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public DreamInfoActionComparator(ComponentName defaultDream) { 5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDefaultDream = defaultDream; 5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public int compare(DreamInfoAction lhs, DreamInfoAction rhs) { 5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return sortKey(lhs).compareTo(sortKey(rhs)); 5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private String sortKey(DreamInfoAction di) { 6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane StringBuilder sb = new StringBuilder(); 6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sb.append(di.mDreamComponentName.equals(mDefaultDream) ? '0' : '1'); 6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sb.append(di.getTitle()); 6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return sb.toString(); 6665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String TAG = "DreamInfoAction"; 7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final ResolveInfo mResolveInfo; 7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final ComponentName mDreamComponentName; 7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private final ComponentName mSettingsComponentName; 7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane DreamInfoAction(ResolveInfo resolveInfo, ComponentName activeDream, PackageManager pm) { 7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this(resolveInfo, activeDream, (String) resolveInfo.loadLabel(pm), getDreamComponentName( 7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane resolveInfo), getSettingsComponentName(resolveInfo, pm)); 7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private DreamInfoAction(ResolveInfo resolveInfo, ComponentName activeDream, String title, 8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ComponentName dreamComponentName, ComponentName settingsComponentName) { 8265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane this(resolveInfo, dreamComponentName.equals(activeDream), title, dreamComponentName, 8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane settingsComponentName); 8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane protected DreamInfoAction(ResolveInfo resolveInfo, boolean checked, String title, 8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ComponentName dreamComponentName, ComponentName settingsComponentName) { 8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane super(null, title, null, null, 0, checked, false, settingsComponentName != null, false, 8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane null, CHECK_SET_ID); 9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mResolveInfo = resolveInfo; 9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mDreamComponentName = dreamComponentName; 9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mSettingsComponentName = settingsComponentName; 9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Drawable getIndicator(Context context) { 9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mResolveInfo.loadIcon(context.getPackageManager()); 9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static Parcelable.Creator<DreamInfoAction> CREATOR = 10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane new Parcelable.Creator<DreamInfoAction>() { 10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public DreamInfoAction createFromParcel(Parcel source) { 10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new DreamInfoAction((ResolveInfo) source.readParcelable(null), 10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane source.readInt() == 1, source.readString(), 10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane (ComponentName) source.readParcelable(null), 10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane (ComponentName) source.readParcelable(null)); 10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public DreamInfoAction[] newArray(int size) { 11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new DreamInfoAction[size]; 11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane }; 11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void writeToParcel(Parcel dest, int flags) { 11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeParcelable(mResolveInfo, flags); 11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeInt(isChecked() ? 1 : 0); 12065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeString(getTitle()); 12165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeParcelable(mDreamComponentName, flags); 12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dest.writeParcelable(mSettingsComponentName, flags); 12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public Intent getSettingsIntent() { 12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (mSettingsComponentName != null) { 12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new Intent().setComponent(mSettingsComponentName); 12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public void setDream(DreamBackend dreamBackend) { 13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!dreamBackend.isEnabled()) { 13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dreamBackend.setEnabled(true); 13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dreamBackend.setActiveDream(mDreamComponentName); 13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane dreamBackend.setActiveDreamInfoAction(this); 13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static ComponentName getDreamComponentName(ResolveInfo resolveInfo) { 14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (resolveInfo == null || resolveInfo.serviceInfo == null) { 14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static ComponentName getSettingsComponentName(ResolveInfo resolveInfo, 14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane PackageManager pm) { 15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (resolveInfo == null || resolveInfo.serviceInfo == null 15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane || resolveInfo.serviceInfo.metaData == null) { 15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String cn = null; 15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane XmlResourceParser parser = null; 15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Exception caughtException = null; 15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane try { 15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA); 15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (parser == null) { 16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data"); 16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); 16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane AttributeSet attrs = Xml.asAttributeSet(parser); 16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int type; 16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane && type != XmlPullParser.START_TAG) { 16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String nodeName = parser.getName(); 17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (!"dream".equals(nodeName)) { 17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "Meta-data does not start with dream tag"); 17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream); 17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane cn = sa.getString(com.android.internal.R.styleable.Dream_settingsActivity); 17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane sa.recycle(); 17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (NameNotFoundException e) { 17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane caughtException = e; 17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (IOException e) { 18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane caughtException = e; 18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (XmlPullParserException e) { 18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane caughtException = e; 18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } finally { 18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (parser != null) { 18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane parser.close(); 18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (caughtException != null) { 18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); 19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return cn == null ? null : ComponentName.unflattenFromString(cn); 19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane} 195