• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.settingslib.dream;
18 
19 import static android.service.dreams.Flags.allowDreamWhenPostured;
20 
21 import android.annotation.IntDef;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ResolveInfo;
28 import android.content.pm.ServiceInfo;
29 import android.content.res.Resources;
30 import android.graphics.drawable.Drawable;
31 import android.os.RemoteException;
32 import android.os.ServiceManager;
33 import android.os.UserHandle;
34 import android.provider.Settings;
35 import android.service.dreams.DreamService;
36 import android.service.dreams.IDreamManager;
37 import android.util.ArraySet;
38 import android.util.Log;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.util.FrameworkStatsLog;
42 
43 import java.lang.annotation.Retention;
44 import java.lang.annotation.RetentionPolicy;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Comparator;
48 import java.util.List;
49 import java.util.Set;
50 import java.util.stream.Collectors;
51 
52 public class DreamBackend {
53     private static final String TAG = "DreamBackend";
54     private static final boolean DEBUG = false;
55 
56     public static class DreamInfo {
57         public CharSequence caption;
58         public Drawable icon;
59         public boolean isActive;
60         public ComponentName componentName;
61         public ComponentName settingsComponentName;
62         public CharSequence description;
63         public Drawable previewImage;
64         public boolean supportsComplications = false;
65         public int dreamCategory;
66 
67         @Override
toString()68         public String toString() {
69             StringBuilder sb = new StringBuilder(DreamInfo.class.getSimpleName());
70             sb.append('[').append(caption);
71             if (isActive) {
72                 sb.append(",active");
73             }
74             sb.append(',').append(componentName);
75             if (settingsComponentName != null) {
76                 sb.append("settings=").append(settingsComponentName);
77             }
78             return sb.append(']').toString();
79         }
80     }
81 
82     @Retention(RetentionPolicy.SOURCE)
83     @IntDef({
84             WHILE_CHARGING,
85             WHILE_DOCKED,
86             WHILE_POSTURED,
87             WHILE_CHARGING_OR_DOCKED,
88             NEVER
89     })
90     public @interface WhenToDream {
91     }
92 
93     public static final int WHILE_CHARGING = 0;
94     public static final int WHILE_DOCKED = 1;
95     public static final int WHILE_POSTURED = 2;
96     public static final int WHILE_CHARGING_OR_DOCKED = 3;
97     public static final int NEVER = 4;
98 
99     /**
100      * The type of dream complications which can be provided by a
101      * {@link com.android.systemui.dreams.ComplicationProvider}.
102      */
103     @IntDef(prefix = {"COMPLICATION_TYPE_"}, value = {
104             COMPLICATION_TYPE_TIME,
105             COMPLICATION_TYPE_DATE,
106             COMPLICATION_TYPE_WEATHER,
107             COMPLICATION_TYPE_AIR_QUALITY,
108             COMPLICATION_TYPE_CAST_INFO,
109             COMPLICATION_TYPE_HOME_CONTROLS,
110             COMPLICATION_TYPE_SMARTSPACE,
111             COMPLICATION_TYPE_MEDIA_ENTRY
112     })
113     @Retention(RetentionPolicy.SOURCE)
114     public @interface ComplicationType {
115     }
116 
117     public static final int COMPLICATION_TYPE_TIME = 1;
118     public static final int COMPLICATION_TYPE_DATE = 2;
119     public static final int COMPLICATION_TYPE_WEATHER = 3;
120     public static final int COMPLICATION_TYPE_AIR_QUALITY = 4;
121     public static final int COMPLICATION_TYPE_CAST_INFO = 5;
122     public static final int COMPLICATION_TYPE_HOME_CONTROLS = 6;
123     public static final int COMPLICATION_TYPE_SMARTSPACE = 7;
124     public static final int COMPLICATION_TYPE_MEDIA_ENTRY = 8;
125 
126     private static final int SCREENSAVER_HOME_CONTROLS_ENABLED_DEFAULT = 1;
127     private static final int LOCKSCREEN_SHOW_CONTROLS_DEFAULT = 0;
128 
129     private static final int DS_TYPE_ENABLED = FrameworkStatsLog
130             .DREAM_SETTING_CHANGED__DREAM_SETTING_TYPE__DREAM_SETTING_TYPE_ENABLED;
131     private static final int DS_TYPE_WHEN_TO_DREAM = FrameworkStatsLog
132             .DREAM_SETTING_CHANGED__DREAM_SETTING_TYPE__DREAM_SETTING_TYPE_WHEN_TO_DREAM;
133     private static final int DS_TYPE_DREAM_COMPONENT = FrameworkStatsLog
134             .DREAM_SETTING_CHANGED__DREAM_SETTING_TYPE__DREAM_SETTING_TYPE_DREAM_COMPONENT;
135     private static final int DS_TYPE_SHOW_ADDITIONAL_INFO = FrameworkStatsLog
136             .DREAM_SETTING_CHANGED__DREAM_SETTING_TYPE__DREAM_SETTING_TYPE_SHOW_ADDITIONAL_INFO;
137     private static final int DS_TYPE_SHOW_HOME_CONTROLS = FrameworkStatsLog
138             .DREAM_SETTING_CHANGED__DREAM_SETTING_TYPE__DREAM_SETTING_TYPE_SHOW_HOME_CONTROLS;
139 
140     private static final int WHEN_TO_DREAM_UNSPECIFIED = FrameworkStatsLog
141             .DREAM_SETTING_CHANGED__WHEN_TO_DREAM__WHEN_TO_DREAM_UNSPECIFIED;
142     private static final int WHEN_TO_DREAM_CHARGING = FrameworkStatsLog
143             .DREAM_SETTING_CHANGED__WHEN_TO_DREAM__WHEN_TO_DREAM_WHILE_CHARGING_ONLY;
144     private static final int WHEN_TO_DREAM_DOCKED = FrameworkStatsLog
145             .DREAM_SETTING_CHANGED__WHEN_TO_DREAM__WHEN_TO_DREAM_WHILE_DOCKED_ONLY;
146     private static final int WHEN_TO_DREAM_POSTURED = FrameworkStatsLog
147             .DREAM_SETTING_CHANGED__WHEN_TO_DREAM__WHEN_TO_DREAM_WHILE_POSTURED_ONLY;
148     private static final int WHEN_TO_DREAM_CHARGING_OR_DOCKED = FrameworkStatsLog
149             .DREAM_SETTING_CHANGED__WHEN_TO_DREAM__WHEN_TO_DREAM_EITHER_CHARGING_OR_DOCKED;
150 
151     private final Context mContext;
152     private final IDreamManager mDreamManager;
153     private final DreamInfoComparator mComparator;
154     private final boolean mDreamsEnabledByDefault;
155     private final boolean mDreamsActivatedOnSleepByDefault;
156     private final boolean mDreamsActivatedOnDockByDefault;
157     private final boolean mDreamsActivatedOnPosturedByDefault;
158     private final Set<ComponentName> mDisabledDreams;
159     private final List<String> mLoggableDreamPrefixes;
160     private Set<Integer> mSupportedComplications;
161     private static DreamBackend sInstance;
162 
getInstance(Context context)163     public static DreamBackend getInstance(Context context) {
164         if (sInstance == null) {
165             sInstance = new DreamBackend(context);
166         }
167         return sInstance;
168     }
169 
DreamBackend(Context context)170     public DreamBackend(Context context) {
171         mContext = context.getApplicationContext();
172         final Resources resources = mContext.getResources();
173 
174         mDreamManager = IDreamManager.Stub.asInterface(
175                 ServiceManager.getService(DreamService.DREAM_SERVICE));
176         mComparator = new DreamInfoComparator(getDefaultDream());
177         mDreamsEnabledByDefault = resources.getBoolean(
178                 com.android.internal.R.bool.config_dreamsEnabledByDefault);
179         mDreamsActivatedOnSleepByDefault = resources.getBoolean(
180                 com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
181         mDreamsActivatedOnDockByDefault = resources.getBoolean(
182                 com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
183         mDreamsActivatedOnPosturedByDefault = resources.getBoolean(
184                 com.android.internal.R.bool.config_dreamsActivatedOnPosturedByDefault);
185         mDisabledDreams = Arrays.stream(resources.getStringArray(
186                         com.android.internal.R.array.config_disabledDreamComponents))
187                 .map(ComponentName::unflattenFromString)
188                 .collect(Collectors.toSet());
189         mLoggableDreamPrefixes = Arrays.stream(resources.getStringArray(
190                 com.android.internal.R.array.config_loggable_dream_prefixes)).toList();
191 
192         mSupportedComplications = Arrays.stream(resources.getIntArray(
193                         com.android.internal.R.array.config_supportedDreamComplications))
194                 .boxed()
195                 .collect(Collectors.toSet());
196     }
197 
getDreamInfos()198     public List<DreamInfo> getDreamInfos() {
199         logd("getDreamInfos()");
200         ComponentName activeDream = getActiveDream();
201         PackageManager pm = mContext.getPackageManager();
202         Intent dreamIntent = new Intent(DreamService.SERVICE_INTERFACE);
203         List<ResolveInfo> resolveInfos = pm.queryIntentServices(dreamIntent,
204                 PackageManager.GET_META_DATA);
205         List<DreamInfo> dreamInfos = new ArrayList<>(resolveInfos.size());
206         for (ResolveInfo resolveInfo : resolveInfos) {
207             final ComponentName componentName = getDreamComponentName(resolveInfo);
208             if (componentName == null || mDisabledDreams.contains(componentName)) {
209                 continue;
210             }
211 
212             DreamInfo dreamInfo = new DreamInfo();
213             dreamInfo.caption = resolveInfo.loadLabel(pm);
214             dreamInfo.icon = resolveInfo.loadIcon(pm);
215             dreamInfo.description = getDescription(resolveInfo, pm);
216             dreamInfo.componentName = componentName;
217             dreamInfo.isActive = dreamInfo.componentName.equals(activeDream);
218 
219             final DreamService.DreamMetadata dreamMetadata = DreamService.getDreamMetadata(
220                     mContext.getPackageManager(), resolveInfo.serviceInfo);
221             if (dreamMetadata != null) {
222                 dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
223                 dreamInfo.previewImage = dreamMetadata.previewImage;
224                 dreamInfo.supportsComplications = dreamMetadata.showComplications;
225                 dreamInfo.dreamCategory = dreamMetadata.dreamCategory;
226             }
227             dreamInfos.add(dreamInfo);
228         }
229         dreamInfos.sort(mComparator);
230         return dreamInfos;
231     }
232 
getDescription(ResolveInfo resolveInfo, PackageManager pm)233     private static CharSequence getDescription(ResolveInfo resolveInfo, PackageManager pm) {
234         String packageName = resolveInfo.resolvePackageName;
235         ApplicationInfo applicationInfo = null;
236         if (packageName == null) {
237             packageName = resolveInfo.serviceInfo.packageName;
238             applicationInfo = resolveInfo.serviceInfo.applicationInfo;
239         }
240         if (resolveInfo.serviceInfo.descriptionRes != 0) {
241             return pm.getText(packageName,
242                     resolveInfo.serviceInfo.descriptionRes,
243                     applicationInfo);
244         }
245         return null;
246     }
247 
getDefaultDream()248     public ComponentName getDefaultDream() {
249         if (mDreamManager == null) {
250             return null;
251         }
252         try {
253             return mDreamManager.getDefaultDreamComponentForUser(mContext.getUserId());
254         } catch (RemoteException e) {
255             Log.w(TAG, "Failed to get default dream", e);
256             return null;
257         }
258     }
259 
getActiveDreamName()260     public CharSequence getActiveDreamName() {
261         ComponentName cn = getActiveDream();
262         if (cn != null) {
263             PackageManager pm = mContext.getPackageManager();
264             try {
265                 ServiceInfo ri = pm.getServiceInfo(cn, 0);
266                 if (ri != null) {
267                     return ri.loadLabel(pm);
268                 }
269             } catch (PackageManager.NameNotFoundException exc) {
270                 return null; // uninstalled?
271             }
272         }
273         return null;
274     }
275 
276     /**
277      * Gets an icon from active dream.
278      */
getActiveIcon()279     public Drawable getActiveIcon() {
280         final ComponentName cn = getActiveDream();
281         if (cn != null) {
282             final PackageManager pm = mContext.getPackageManager();
283             try {
284                 final ServiceInfo ri = pm.getServiceInfo(cn, 0);
285                 if (ri != null) {
286                     return ri.loadIcon(pm);
287                 }
288             } catch (PackageManager.NameNotFoundException exc) {
289                 return null;
290             }
291         }
292         return null;
293     }
294 
295     @WhenToDream
getWhenToDreamSetting()296     public int getWhenToDreamSetting() {
297         return isActivatedOnDock() && isActivatedOnSleep() ? WHILE_CHARGING_OR_DOCKED
298                 : isActivatedOnSleep() ? WHILE_CHARGING
299                         : isActivatedOnDock() ? WHILE_DOCKED
300                                 : isActivatedOnPostured() ? WHILE_POSTURED
301                                         : NEVER;
302     }
303 
setWhenToDream(@henToDream int whenToDream)304     public void setWhenToDream(@WhenToDream int whenToDream) {
305         setEnabled(whenToDream != NEVER);
306 
307         switch (whenToDream) {
308             case WHILE_CHARGING:
309                 setActivatedOnDock(false);
310                 setActivatedOnSleep(true);
311                 setActivatedOnPostured(false);
312                 break;
313 
314             case WHILE_DOCKED:
315                 setActivatedOnDock(true);
316                 setActivatedOnSleep(false);
317                 setActivatedOnPostured(false);
318                 break;
319 
320             case WHILE_CHARGING_OR_DOCKED:
321                 setActivatedOnDock(true);
322                 setActivatedOnSleep(true);
323                 setActivatedOnPostured(false);
324                 break;
325 
326             case WHILE_POSTURED:
327                 setActivatedOnPostured(true);
328                 setActivatedOnSleep(false);
329                 setActivatedOnDock(false);
330                 break;
331 
332             case NEVER:
333             default:
334                 break;
335         }
336 
337         logDreamSettingChangeToStatsd(DS_TYPE_WHEN_TO_DREAM);
338     }
339 
340     /** Gets all complications which have been enabled by the user. */
getEnabledComplications()341     public Set<Integer> getEnabledComplications() {
342         final Set<Integer> enabledComplications =
343                 getComplicationsEnabled()
344                         ? new ArraySet<>(mSupportedComplications) : new ArraySet<>();
345 
346         if (!getHomeControlsEnabled()) {
347             enabledComplications.remove(COMPLICATION_TYPE_HOME_CONTROLS);
348         } else if (mSupportedComplications.contains(COMPLICATION_TYPE_HOME_CONTROLS)) {
349             // Add home control type to list of enabled complications, even if other complications
350             // have been disabled.
351             enabledComplications.add(COMPLICATION_TYPE_HOME_CONTROLS);
352         }
353         return enabledComplications;
354     }
355 
356     /** Sets complication enabled state. */
setComplicationsEnabled(boolean enabled)357     public void setComplicationsEnabled(boolean enabled) {
358         Settings.Secure.putInt(mContext.getContentResolver(),
359                 Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED, enabled ? 1 : 0);
360         logDreamSettingChangeToStatsd(DS_TYPE_SHOW_ADDITIONAL_INFO);
361     }
362 
363     /** Sets whether home controls are enabled by the user on the dream */
setHomeControlsEnabled(boolean enabled)364     public void setHomeControlsEnabled(boolean enabled) {
365         Settings.Secure.putInt(mContext.getContentResolver(),
366                 Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, enabled ? 1 : 0);
367         logDreamSettingChangeToStatsd(DS_TYPE_SHOW_HOME_CONTROLS);
368     }
369 
370     /** Gets whether home controls button is enabled on the dream */
getHomeControlsEnabled()371     private boolean getHomeControlsEnabled() {
372         return Settings.Secure.getInt(
373                 mContext.getContentResolver(),
374                 Settings.Secure.LOCKSCREEN_SHOW_CONTROLS,
375                 LOCKSCREEN_SHOW_CONTROLS_DEFAULT) == 1
376                 && Settings.Secure.getInt(
377                         mContext.getContentResolver(),
378                         Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
379                         SCREENSAVER_HOME_CONTROLS_ENABLED_DEFAULT) == 1;
380     }
381 
382     /**
383      * Gets whether complications are enabled on this device
384      */
getComplicationsEnabled()385     public boolean getComplicationsEnabled() {
386         return Settings.Secure.getInt(
387                 mContext.getContentResolver(),
388                 Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED, 1) == 1;
389     }
390 
391     /** Gets all dream complications which are supported on this device. **/
getSupportedComplications()392     public Set<Integer> getSupportedComplications() {
393         return mSupportedComplications;
394     }
395 
396     /**
397      * Sets the list of supported complications. Should only be used in tests.
398      */
399     @VisibleForTesting
setSupportedComplications(Set<Integer> complications)400     public void setSupportedComplications(Set<Integer> complications) {
401         mSupportedComplications = complications;
402     }
403 
isEnabled()404     public boolean isEnabled() {
405         return getBoolean(Settings.Secure.SCREENSAVER_ENABLED, mDreamsEnabledByDefault);
406     }
407 
setEnabled(boolean value)408     public void setEnabled(boolean value) {
409         logd("setEnabled(%s)", value);
410         setBoolean(Settings.Secure.SCREENSAVER_ENABLED, value);
411         logDreamSettingChangeToStatsd(DS_TYPE_ENABLED);
412     }
413 
isActivatedOnDock()414     public boolean isActivatedOnDock() {
415         return getBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
416                 mDreamsActivatedOnDockByDefault);
417     }
418 
setActivatedOnDock(boolean value)419     public void setActivatedOnDock(boolean value) {
420         logd("setActivatedOnDock(%s)", value);
421         setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, value);
422     }
423 
isActivatedOnSleep()424     public boolean isActivatedOnSleep() {
425         return getBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
426                 mDreamsActivatedOnSleepByDefault);
427     }
428 
setActivatedOnSleep(boolean value)429     public void setActivatedOnSleep(boolean value) {
430         logd("setActivatedOnSleep(%s)", value);
431         setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, value);
432     }
433 
isActivatedOnPostured()434     public boolean isActivatedOnPostured() {
435         return allowDreamWhenPostured()
436                 && getBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED,
437                         mDreamsActivatedOnPosturedByDefault);
438     }
439 
440     /**
441      * Sets whether dreams should be activated when the device is postured (stationary and upright)
442      */
setActivatedOnPostured(boolean value)443     public void setActivatedOnPostured(boolean value) {
444         if (allowDreamWhenPostured()) {
445             logd("setActivatedOnPostured(%s)", value);
446             setBoolean(Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, value);
447         }
448     }
449 
getBoolean(String key, boolean def)450     private boolean getBoolean(String key, boolean def) {
451         return Settings.Secure.getInt(mContext.getContentResolver(), key, def ? 1 : 0) == 1;
452     }
453 
setBoolean(String key, boolean value)454     private void setBoolean(String key, boolean value) {
455         Settings.Secure.putInt(mContext.getContentResolver(), key, value ? 1 : 0);
456     }
457 
setActiveDream(ComponentName dream)458     public void setActiveDream(ComponentName dream) {
459         logd("setActiveDream(%s)", dream);
460         if (mDreamManager == null) {
461             return;
462         }
463         try {
464             ComponentName[] dreams = {dream};
465             mDreamManager.setDreamComponents(dream == null ? null : dreams);
466             logDreamSettingChangeToStatsd(DS_TYPE_DREAM_COMPONENT);
467         } catch (RemoteException e) {
468             Log.w(TAG, "Failed to set active dream to " + dream, e);
469         }
470     }
471 
getActiveDream()472     public ComponentName getActiveDream() {
473         if (mDreamManager == null) {
474             return null;
475         }
476         try {
477             ComponentName[] dreams = mDreamManager.getDreamComponents();
478             return dreams != null && dreams.length > 0 ? dreams[0] : null;
479         } catch (RemoteException e) {
480             Log.w(TAG, "Failed to get active dream", e);
481             return null;
482         }
483     }
484 
launchSettings(Context uiContext, DreamInfo dreamInfo)485     public void launchSettings(Context uiContext, DreamInfo dreamInfo) {
486         logd("launchSettings(%s)", dreamInfo);
487         if (dreamInfo == null || dreamInfo.settingsComponentName == null) {
488             return;
489         }
490         final Intent intent = new Intent()
491                 .setComponent(dreamInfo.settingsComponentName)
492                 .addFlags(
493                         Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
494         uiContext.startActivity(intent);
495     }
496 
497     /**
498      * Preview a dream, given the component name.
499      */
preview(ComponentName componentName)500     public void preview(ComponentName componentName) {
501         logd("preview(%s)", componentName);
502         if (mDreamManager == null || componentName == null) {
503             return;
504         }
505         try {
506             mDreamManager.testDream(mContext.getUserId(), componentName);
507         } catch (RemoteException e) {
508             Log.w(TAG, "Failed to preview " + componentName, e);
509         }
510     }
511 
startDreaming()512     public void startDreaming() {
513         logd("startDreaming()");
514         if (mDreamManager == null) {
515             return;
516         }
517         try {
518             mDreamManager.dream();
519         } catch (RemoteException e) {
520             Log.w(TAG, "Failed to dream", e);
521         }
522     }
523 
getDreamComponentName(ResolveInfo resolveInfo)524     private static ComponentName getDreamComponentName(ResolveInfo resolveInfo) {
525         if (resolveInfo == null || resolveInfo.serviceInfo == null) {
526             return null;
527         }
528         return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
529     }
530 
logd(String msg, Object... args)531     private static void logd(String msg, Object... args) {
532         if (DEBUG) {
533             Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
534         }
535     }
536 
logDreamSettingChangeToStatsd(int dreamSettingType)537     private void logDreamSettingChangeToStatsd(int dreamSettingType) {
538         FrameworkStatsLog.write(
539                 FrameworkStatsLog.DREAM_SETTING_CHANGED, /*atom_tag*/
540                 UserHandle.myUserId(), /*uid*/
541                 isEnabled(), /*enabled*/
542                 getActiveDreamComponentForStatsd(), /*dream_component*/
543                 getWhenToDreamForStatsd(), /*when_to_dream*/
544                 getComplicationsEnabled(), /*show_additional_info*/
545                 getHomeControlsEnabled(), /*show_home_controls*/
546                 dreamSettingType /*dream_setting_type*/
547         );
548     }
549 
550     /**
551      * Returns the user selected dream component in string format for stats logging. If the dream
552      * component is not loggable, returns "other".
553      */
getActiveDreamComponentForStatsd()554     private String getActiveDreamComponentForStatsd() {
555         final ComponentName activeDream = getActiveDream();
556         if (activeDream == null) {
557             return "";
558         }
559 
560         final String component = activeDream.flattenToShortString();
561         if (isLoggableDreamComponentForStatsd(component)) {
562             return component;
563         } else {
564             return "other";
565         }
566     }
567 
568     /**
569      * Whether the dream component is loggable. Only components from the predefined packages are
570      * allowed to be logged for privacy.
571      */
isLoggableDreamComponentForStatsd(String component)572     private boolean isLoggableDreamComponentForStatsd(String component) {
573         for (int i = 0; i < mLoggableDreamPrefixes.size(); i++) {
574             if (component.startsWith(mLoggableDreamPrefixes.get(i))) {
575                 return true;
576             }
577         }
578 
579         return false;
580     }
581 
582     /**
583      * Returns the enum of "when to dream" setting for statsd logging.
584      */
getWhenToDreamForStatsd()585     private int getWhenToDreamForStatsd() {
586         switch (getWhenToDreamSetting()) {
587             case WHILE_CHARGING:
588                 return WHEN_TO_DREAM_CHARGING;
589             case WHILE_DOCKED:
590                 return WHEN_TO_DREAM_DOCKED;
591             case WHILE_POSTURED:
592                 return WHEN_TO_DREAM_POSTURED;
593             case WHILE_CHARGING_OR_DOCKED:
594                 return WHEN_TO_DREAM_CHARGING_OR_DOCKED;
595             case NEVER:
596             default:
597                 return WHEN_TO_DREAM_UNSPECIFIED;
598         }
599     }
600 
601     private static class DreamInfoComparator implements Comparator<DreamInfo> {
602         private final ComponentName mDefaultDream;
603 
DreamInfoComparator(ComponentName defaultDream)604         public DreamInfoComparator(ComponentName defaultDream) {
605             mDefaultDream = defaultDream;
606         }
607 
608         @Override
compare(DreamInfo lhs, DreamInfo rhs)609         public int compare(DreamInfo lhs, DreamInfo rhs) {
610             return sortKey(lhs).compareTo(sortKey(rhs));
611         }
612 
sortKey(DreamInfo di)613         private String sortKey(DreamInfo di) {
614             StringBuilder sb = new StringBuilder();
615             sb.append(di.componentName.equals(mDefaultDream) ? '0' : '1');
616             sb.append(di.caption);
617             return sb.toString();
618         }
619     }
620 }
621