blob: e5cdc85a48d959a99a6f5281e8eba481c7a2a432 [file] [log] [blame]
Tony Mantlere43853c2015-10-09 14:37:32 -07001/*
2 * Copyright (C) 2015 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.settingslib.dream;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.pm.PackageManager;
23import android.content.pm.ResolveInfo;
24import android.content.pm.ServiceInfo;
25import android.content.res.Resources;
26import android.content.res.TypedArray;
27import android.content.res.XmlResourceParser;
28import android.graphics.drawable.Drawable;
29import android.os.RemoteException;
30import android.os.ServiceManager;
31import android.provider.Settings;
32import android.service.dreams.DreamService;
33import android.service.dreams.IDreamManager;
34import android.util.AttributeSet;
35import android.util.Log;
36import android.util.Xml;
37
38import org.xmlpull.v1.XmlPullParser;
39import org.xmlpull.v1.XmlPullParserException;
40
41import java.io.IOException;
42import java.util.ArrayList;
43import java.util.Collections;
44import java.util.Comparator;
45import java.util.List;
46
47public class DreamBackend {
48 private static final String TAG = "DreamBackend";
49 private static final boolean DEBUG = false;
50
51 public static class DreamInfo {
52 public CharSequence caption;
53 public Drawable icon;
54 public boolean isActive;
55 public ComponentName componentName;
56 public ComponentName settingsComponentName;
57
58 @Override
59 public String toString() {
60 StringBuilder sb = new StringBuilder(DreamInfo.class.getSimpleName());
61 sb.append('[').append(caption);
62 if (isActive)
63 sb.append(",active");
64 sb.append(',').append(componentName);
65 if (settingsComponentName != null)
66 sb.append("settings=").append(settingsComponentName);
67 return sb.append(']').toString();
68 }
69 }
70
71 private final Context mContext;
72 private final IDreamManager mDreamManager;
73 private final DreamInfoComparator mComparator;
74 private final boolean mDreamsEnabledByDefault;
75 private final boolean mDreamsActivatedOnSleepByDefault;
76 private final boolean mDreamsActivatedOnDockByDefault;
77
78 public DreamBackend(Context context) {
79 mContext = context;
80 mDreamManager = IDreamManager.Stub.asInterface(
81 ServiceManager.getService(DreamService.DREAM_SERVICE));
82 mComparator = new DreamInfoComparator(getDefaultDream());
83 mDreamsEnabledByDefault = context.getResources()
84 .getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault);
85 mDreamsActivatedOnSleepByDefault = context.getResources()
86 .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
87 mDreamsActivatedOnDockByDefault = context.getResources()
88 .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
89 }
90
91 public List<DreamInfo> getDreamInfos() {
92 logd("getDreamInfos()");
93 ComponentName activeDream = getActiveDream();
94 PackageManager pm = mContext.getPackageManager();
95 Intent dreamIntent = new Intent(DreamService.SERVICE_INTERFACE);
96 List<ResolveInfo> resolveInfos = pm.queryIntentServices(dreamIntent,
97 PackageManager.GET_META_DATA);
98 List<DreamInfo> dreamInfos = new ArrayList<>(resolveInfos.size());
99 for (ResolveInfo resolveInfo : resolveInfos) {
100 if (resolveInfo.serviceInfo == null)
101 continue;
102 DreamInfo dreamInfo = new DreamInfo();
103 dreamInfo.caption = resolveInfo.loadLabel(pm);
104 dreamInfo.icon = resolveInfo.loadIcon(pm);
105 dreamInfo.componentName = getDreamComponentName(resolveInfo);
106 dreamInfo.isActive = dreamInfo.componentName.equals(activeDream);
107 dreamInfo.settingsComponentName = getSettingsComponentName(pm, resolveInfo);
108 dreamInfos.add(dreamInfo);
109 }
110 Collections.sort(dreamInfos, mComparator);
111 return dreamInfos;
112 }
113
114 public ComponentName getDefaultDream() {
115 if (mDreamManager == null)
116 return null;
117 try {
118 return mDreamManager.getDefaultDreamComponent();
119 } catch (RemoteException e) {
120 Log.w(TAG, "Failed to get default dream", e);
121 return null;
122 }
123 }
124
125 public CharSequence getActiveDreamName() {
126 ComponentName cn = getActiveDream();
127 if (cn != null) {
128 PackageManager pm = mContext.getPackageManager();
129 try {
130 ServiceInfo ri = pm.getServiceInfo(cn, 0);
131 if (ri != null) {
132 return ri.loadLabel(pm);
133 }
134 } catch (PackageManager.NameNotFoundException exc) {
135 return null; // uninstalled?
136 }
137 }
138 return null;
139 }
140
141 public boolean isEnabled() {
142 return getBoolean(Settings.Secure.SCREENSAVER_ENABLED, mDreamsEnabledByDefault);
143 }
144
145 public void setEnabled(boolean value) {
146 logd("setEnabled(%s)", value);
147 setBoolean(Settings.Secure.SCREENSAVER_ENABLED, value);
148 }
149
150 public boolean isActivatedOnDock() {
151 return getBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
152 mDreamsActivatedOnDockByDefault);
153 }
154
155 public void setActivatedOnDock(boolean value) {
156 logd("setActivatedOnDock(%s)", value);
157 setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, value);
158 }
159
160 public boolean isActivatedOnSleep() {
161 return getBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
162 mDreamsActivatedOnSleepByDefault);
163 }
164
165 public void setActivatedOnSleep(boolean value) {
166 logd("setActivatedOnSleep(%s)", value);
167 setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, value);
168 }
169
170 private boolean getBoolean(String key, boolean def) {
171 return Settings.Secure.getInt(mContext.getContentResolver(), key, def ? 1 : 0) == 1;
172 }
173
174 private void setBoolean(String key, boolean value) {
175 Settings.Secure.putInt(mContext.getContentResolver(), key, value ? 1 : 0);
176 }
177
178 public void setActiveDream(ComponentName dream) {
179 logd("setActiveDream(%s)", dream);
180 if (mDreamManager == null)
181 return;
182 try {
183 ComponentName[] dreams = { dream };
184 mDreamManager.setDreamComponents(dream == null ? null : dreams);
185 } catch (RemoteException e) {
186 Log.w(TAG, "Failed to set active dream to " + dream, e);
187 }
188 }
189
190 public ComponentName getActiveDream() {
191 if (mDreamManager == null)
192 return null;
193 try {
194 ComponentName[] dreams = mDreamManager.getDreamComponents();
195 return dreams != null && dreams.length > 0 ? dreams[0] : null;
196 } catch (RemoteException e) {
197 Log.w(TAG, "Failed to get active dream", e);
198 return null;
199 }
200 }
201
202 public void launchSettings(DreamInfo dreamInfo) {
203 logd("launchSettings(%s)", dreamInfo);
204 if (dreamInfo == null || dreamInfo.settingsComponentName == null)
205 return;
206 mContext.startActivity(new Intent().setComponent(dreamInfo.settingsComponentName));
207 }
208
209 public void preview(DreamInfo dreamInfo) {
210 logd("preview(%s)", dreamInfo);
211 if (mDreamManager == null || dreamInfo == null || dreamInfo.componentName == null)
212 return;
213 try {
214 mDreamManager.testDream(dreamInfo.componentName);
215 } catch (RemoteException e) {
216 Log.w(TAG, "Failed to preview " + dreamInfo, e);
217 }
218 }
219
220 public void startDreaming() {
221 logd("startDreaming()");
222 if (mDreamManager == null)
223 return;
224 try {
225 mDreamManager.dream();
226 } catch (RemoteException e) {
227 Log.w(TAG, "Failed to dream", e);
228 }
229 }
230
231 private static ComponentName getDreamComponentName(ResolveInfo resolveInfo) {
232 if (resolveInfo == null || resolveInfo.serviceInfo == null)
233 return null;
234 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
235 }
236
237 private static ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
238 if (resolveInfo == null
239 || resolveInfo.serviceInfo == null
240 || resolveInfo.serviceInfo.metaData == null)
241 return null;
242 String cn = null;
243 XmlResourceParser parser = null;
244 Exception caughtException = null;
245 try {
246 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA);
247 if (parser == null) {
248 Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data");
249 return null;
250 }
251 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
252 AttributeSet attrs = Xml.asAttributeSet(parser);
253 int type;
254 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
255 && type != XmlPullParser.START_TAG) {
256 }
257 String nodeName = parser.getName();
258 if (!"dream".equals(nodeName)) {
259 Log.w(TAG, "Meta-data does not start with dream tag");
260 return null;
261 }
262 TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
263 cn = sa.getString(com.android.internal.R.styleable.Dream_settingsActivity);
264 sa.recycle();
265 } catch (PackageManager.NameNotFoundException|IOException|XmlPullParserException e) {
266 caughtException = e;
267 } finally {
268 if (parser != null) parser.close();
269 }
270 if (caughtException != null) {
271 Log.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
272 return null;
273 }
274 if (cn != null && cn.indexOf('/') < 0) {
275 cn = resolveInfo.serviceInfo.packageName + "/" + cn;
276 }
277 return cn == null ? null : ComponentName.unflattenFromString(cn);
278 }
279
280 private static void logd(String msg, Object... args) {
281 if (DEBUG)
282 Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
283 }
284
285 private static class DreamInfoComparator implements Comparator<DreamInfo> {
286 private final ComponentName mDefaultDream;
287
288 public DreamInfoComparator(ComponentName defaultDream) {
289 mDefaultDream = defaultDream;
290 }
291
292 @Override
293 public int compare(DreamInfo lhs, DreamInfo rhs) {
294 return sortKey(lhs).compareTo(sortKey(rhs));
295 }
296
297 private String sortKey(DreamInfo di) {
298 StringBuilder sb = new StringBuilder();
299 sb.append(di.componentName.equals(mDefaultDream) ? '0' : '1');
300 sb.append(di.caption);
301 return sb.toString();
302 }
303 }
304}