1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.tv.settings.device.display.daydream; 18 19import com.android.tv.settings.R; 20import com.android.tv.settings.dialog.old.Action; 21 22import android.content.ComponentName; 23import android.content.Context; 24import android.content.Intent; 25import android.content.pm.PackageManager; 26import android.content.pm.ResolveInfo; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.content.res.Resources; 29import android.content.res.TypedArray; 30import android.content.res.XmlResourceParser; 31import android.graphics.drawable.Drawable; 32import android.os.Parcel; 33import android.os.Parcelable; 34import android.service.dreams.DreamService; 35import android.util.AttributeSet; 36import android.util.Log; 37import android.util.Xml; 38 39import org.xmlpull.v1.XmlPullParser; 40import org.xmlpull.v1.XmlPullParserException; 41 42import java.io.IOException; 43import java.util.Comparator; 44 45public class DreamInfoAction extends Action { 46 47 private static final int CHECK_SET_ID = 1; 48 49 static class DreamInfoActionComparator implements Comparator<DreamInfoAction> { 50 private final ComponentName mDefaultDream; 51 52 public DreamInfoActionComparator(ComponentName defaultDream) { 53 mDefaultDream = defaultDream; 54 } 55 56 @Override 57 public int compare(DreamInfoAction lhs, DreamInfoAction rhs) { 58 return sortKey(lhs).compareTo(sortKey(rhs)); 59 } 60 61 private String sortKey(DreamInfoAction di) { 62 StringBuilder sb = new StringBuilder(); 63 sb.append(di.mDreamComponentName.equals(mDefaultDream) ? '0' : '1'); 64 sb.append(di.getTitle()); 65 return sb.toString(); 66 } 67 } 68 69 private static final String TAG = "DreamInfoAction"; 70 71 private final ResolveInfo mResolveInfo; 72 private final ComponentName mDreamComponentName; 73 private final ComponentName mSettingsComponentName; 74 75 DreamInfoAction(ResolveInfo resolveInfo, ComponentName activeDream, PackageManager pm) { 76 this(resolveInfo, activeDream, (String) resolveInfo.loadLabel(pm), getDreamComponentName( 77 resolveInfo), getSettingsComponentName(resolveInfo, pm)); 78 } 79 80 private DreamInfoAction(ResolveInfo resolveInfo, ComponentName activeDream, String title, 81 ComponentName dreamComponentName, ComponentName settingsComponentName) { 82 this(resolveInfo, dreamComponentName.equals(activeDream), title, dreamComponentName, 83 settingsComponentName); 84 } 85 86 protected DreamInfoAction(ResolveInfo resolveInfo, boolean checked, String title, 87 ComponentName dreamComponentName, ComponentName settingsComponentName) { 88 super(null, title, null, null, 0, checked, false, settingsComponentName != null, false, 89 null, CHECK_SET_ID); 90 mResolveInfo = resolveInfo; 91 mDreamComponentName = dreamComponentName; 92 mSettingsComponentName = settingsComponentName; 93 } 94 95 public Drawable getIndicator(Context context) { 96 return mResolveInfo.loadIcon(context.getPackageManager()); 97 } 98 99 public static Parcelable.Creator<DreamInfoAction> CREATOR = 100 new Parcelable.Creator<DreamInfoAction>() { 101 102 @Override 103 public DreamInfoAction createFromParcel(Parcel source) { 104 return new DreamInfoAction((ResolveInfo) source.readParcelable(null), 105 source.readInt() == 1, source.readString(), 106 (ComponentName) source.readParcelable(null), 107 (ComponentName) source.readParcelable(null)); 108 } 109 110 @Override 111 public DreamInfoAction[] newArray(int size) { 112 return new DreamInfoAction[size]; 113 } 114 }; 115 116 @Override 117 public void writeToParcel(Parcel dest, int flags) { 118 dest.writeParcelable(mResolveInfo, flags); 119 dest.writeInt(isChecked() ? 1 : 0); 120 dest.writeString(getTitle()); 121 dest.writeParcelable(mDreamComponentName, flags); 122 dest.writeParcelable(mSettingsComponentName, flags); 123 } 124 125 public Intent getSettingsIntent() { 126 if (mSettingsComponentName != null) { 127 return new Intent().setComponent(mSettingsComponentName); 128 } else { 129 return null; 130 } 131 } 132 133 public void setDream(DreamBackend dreamBackend) { 134 if (!dreamBackend.isEnabled()) { 135 dreamBackend.setEnabled(true); 136 } 137 dreamBackend.setActiveDream(mDreamComponentName); 138 dreamBackend.setActiveDreamInfoAction(this); 139 } 140 141 private static ComponentName getDreamComponentName(ResolveInfo resolveInfo) { 142 if (resolveInfo == null || resolveInfo.serviceInfo == null) { 143 return null; 144 } 145 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 146 } 147 148 private static ComponentName getSettingsComponentName(ResolveInfo resolveInfo, 149 PackageManager pm) { 150 if (resolveInfo == null || resolveInfo.serviceInfo == null 151 || resolveInfo.serviceInfo.metaData == null) { 152 return null; 153 } 154 String cn = null; 155 XmlResourceParser parser = null; 156 Exception caughtException = null; 157 try { 158 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA); 159 if (parser == null) { 160 Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data"); 161 return null; 162 } 163 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); 164 AttributeSet attrs = Xml.asAttributeSet(parser); 165 int type; 166 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 167 && type != XmlPullParser.START_TAG) { 168 } 169 String nodeName = parser.getName(); 170 if (!"dream".equals(nodeName)) { 171 Log.w(TAG, "Meta-data does not start with dream tag"); 172 return null; 173 } 174 TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream); 175 cn = sa.getString(com.android.internal.R.styleable.Dream_settingsActivity); 176 sa.recycle(); 177 } catch (NameNotFoundException e) { 178 caughtException = e; 179 } catch (IOException e) { 180 caughtException = e; 181 } catch (XmlPullParserException e) { 182 caughtException = e; 183 } finally { 184 if (parser != null) { 185 parser.close(); 186 } 187 } 188 if (caughtException != null) { 189 Log.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); 190 return null; 191 } 192 return cn == null ? null : ComponentName.unflattenFromString(cn); 193 } 194} 195