1 /*
2  * Copyright (C) 2012 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 android.service.dreams;
18 
19 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20 import static android.service.dreams.Flags.dreamHandlesConfirmKeys;
21 import static android.service.dreams.Flags.dreamHandlesBeingObscured;
22 
23 import android.annotation.FlaggedApi;
24 import android.annotation.IdRes;
25 import android.annotation.IntDef;
26 import android.annotation.LayoutRes;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.annotation.SdkConstant;
30 import android.annotation.SdkConstant.SdkConstantType;
31 import android.annotation.TestApi;
32 import android.app.Activity;
33 import android.app.AlarmManager;
34 import android.app.KeyguardManager;
35 import android.app.Service;
36 import android.compat.annotation.UnsupportedAppUsage;
37 import android.content.ComponentName;
38 import android.content.Context;
39 import android.content.Intent;
40 import android.content.pm.PackageManager;
41 import android.content.pm.ServiceInfo;
42 import android.content.res.Resources;
43 import android.content.res.TypedArray;
44 import android.graphics.drawable.Drawable;
45 import android.os.Binder;
46 import android.os.Build;
47 import android.os.Handler;
48 import android.os.IBinder;
49 import android.os.IRemoteCallback;
50 import android.os.Looper;
51 import android.os.PowerManager;
52 import android.os.RemoteException;
53 import android.os.ServiceManager;
54 import android.service.controls.flags.Flags;
55 import android.service.dreams.utils.DreamAccessibility;
56 import android.util.Log;
57 import android.util.MathUtils;
58 import android.util.Slog;
59 import android.view.ActionMode;
60 import android.view.Display;
61 import android.view.KeyEvent;
62 import android.view.Menu;
63 import android.view.MenuItem;
64 import android.view.MotionEvent;
65 import android.view.SearchEvent;
66 import android.view.View;
67 import android.view.ViewGroup;
68 import android.view.Window;
69 import android.view.WindowInsets;
70 import android.view.WindowManager;
71 import android.view.WindowManager.LayoutParams;
72 import android.view.accessibility.AccessibilityEvent;
73 
74 import com.android.internal.R;
75 import com.android.internal.annotations.VisibleForTesting;
76 import com.android.internal.util.DumpUtils;
77 
78 import java.io.FileDescriptor;
79 import java.io.PrintWriter;
80 import java.lang.annotation.Retention;
81 import java.lang.annotation.RetentionPolicy;
82 import java.util.function.Consumer;
83 
84 /**
85  * Extend this class to implement a custom dream (available to the user as a "Daydream").
86  *
87  * <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a
88  * desk dock. Dreams provide another modality for apps to express themselves, tailored for
89  * an exhibition/lean-back experience.</p>
90  *
91  * <p>The {@code DreamService} lifecycle is as follows:</p>
92  * <ol>
93  *   <li>{@link #onAttachedToWindow}
94  *     <p>Use this for initial setup, such as calling {@link #setContentView setContentView()}.</li>
95  *   <li>{@link #onDreamingStarted}
96  *     <p>Your dream has started, so you should begin animations or other behaviors here.</li>
97  *   <li>{@link #onDreamingStopped}
98  *     <p>Use this to stop the things you started in {@link #onDreamingStarted}.</li>
99  *   <li>{@link #onDetachedFromWindow}
100  *     <p>Use this to dismantle resources (for example, detach from handlers
101  *        and listeners).</li>
102  * </ol>
103  *
104  * <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
105  * initialization and teardown should be done by overriding the hooks above.</p>
106  *
107  * <p>To be available to the system, your {@code DreamService} should be declared in the
108  * manifest as follows:</p>
109  * <pre>
110  * &lt;service
111  *     android:name=".MyDream"
112  *     android:exported="true"
113  *     android:icon="@drawable/my_icon"
114  *     android:label="@string/my_dream_label" >
115  *
116  *     &lt;intent-filter>
117  *         &lt;action android:name="android.service.dreams.DreamService" />
118  *         &lt;category android:name="android.intent.category.DEFAULT" />
119  *     &lt;/intent-filter>
120  *
121  *     &lt;!-- Point to additional information for this dream (optional) -->
122  *     &lt;meta-data
123  *         android:name="android.service.dream"
124  *         android:resource="@xml/my_dream" />
125  * &lt;/service>
126  * </pre>
127  *
128  * <p>If specified with the {@code <meta-data>} element,
129  * additional information for the dream is defined using the
130  * {@link android.R.styleable#Dream &lt;dream&gt;} element in a separate XML file.
131  * Currently, the only additional
132  * information you can provide is for a settings activity that allows the user to configure
133  * the dream behavior. For example:</p>
134  * <p class="code-caption">res/xml/my_dream.xml</p>
135  * <pre>
136  * &lt;dream xmlns:android="http://schemas.android.com/apk/res/android"
137  *     android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
138  * </pre>
139  * <p>This makes a Settings button available alongside your dream's listing in the
140  * system settings, which when pressed opens the specified activity.</p>
141  *
142  *
143  * <p>To specify your dream layout, call {@link #setContentView}, typically during the
144  * {@link #onAttachedToWindow} callback. For example:</p>
145  * <pre>
146  * public class MyDream extends DreamService {
147  *
148  *     &#64;Override
149  *     public void onAttachedToWindow() {
150  *         super.onAttachedToWindow();
151  *
152  *         // Exit dream upon user touch
153  *         setInteractive(false);
154  *         // Hide system UI
155  *         setFullscreen(true);
156  *         // Set the dream layout
157  *         setContentView(R.layout.dream);
158  *     }
159  * }
160  * </pre>
161  *
162  * <p>When targeting api level 21 and above, you must declare the service in your manifest file
163  * with the {@link android.Manifest.permission#BIND_DREAM_SERVICE} permission. For example:</p>
164  * <pre>
165  * &lt;service
166  *     android:name=".MyDream"
167  *     android:exported="true"
168  *     android:icon="@drawable/my_icon"
169  *     android:label="@string/my_dream_label"
170  *     android:permission="android.permission.BIND_DREAM_SERVICE">
171  *   &lt;intent-filter>
172  *     &lt;action android:name=”android.service.dreams.DreamService” />
173  *     &lt;category android:name=”android.intent.category.DEFAULT” />
174  *   &lt;/intent-filter>
175  * &lt;/service>
176  * </pre>
177  */
178 public class DreamService extends Service implements Window.Callback {
179     private static final String TAG = DreamService.class.getSimpleName();
180     private final String mTag = TAG + "[" + getClass().getSimpleName() + "]";
181     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
182 
183     /**
184      * The name of the dream manager service.
185      * @hide
186      */
187     public static final String DREAM_SERVICE = "dreams";
188 
189     /**
190      * The {@link Intent} that must be declared as handled by the service.
191      */
192     @SdkConstant(SdkConstantType.SERVICE_ACTION)
193     public static final String SERVICE_INTERFACE =
194             "android.service.dreams.DreamService";
195 
196     /**
197      * Name under which a Dream publishes information about itself.
198      * This meta-data must reference an XML resource containing
199      * a <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code>
200      * tag.
201      */
202     public static final String DREAM_META_DATA = "android.service.dream";
203 
204     /**
205      * Name of the root tag under which a Dream defines its metadata in an XML file.
206      */
207     private static final String DREAM_META_DATA_ROOT_TAG = "dream";
208 
209     /**
210      * The default value for whether to show complications on the overlay.
211      *
212      * @hide
213      */
214     public static final boolean DEFAULT_SHOW_COMPLICATIONS = false;
215 
216     /**
217      * The default value for dream category
218      * @hide
219      */
220     @VisibleForTesting
221     public static final int DREAM_CATEGORY_DEFAULT = 0;
222 
223     /**
224      * Dream category for Low Light Dream
225      * @hide
226      */
227     public static final int DREAM_CATEGORY_LOW_LIGHT = 1 << 0;
228 
229     /**
230      * Dream category for Home Panel Dream
231      * @hide
232      */
233     public static final int DREAM_CATEGORY_HOME_PANEL = 1 << 1;
234 
235     /** @hide */
236     @IntDef(flag = true, prefix = {"DREAM_CATEGORY"}, value = {
237         DREAM_CATEGORY_DEFAULT,
238         DREAM_CATEGORY_LOW_LIGHT,
239         DREAM_CATEGORY_HOME_PANEL
240     })
241     @Retention(RetentionPolicy.SOURCE)
242     @interface DreamCategory {}
243 
244     /**
245      * The name of the extra where the dream overlay component is stored.
246      */
247     static final String EXTRA_DREAM_OVERLAY_COMPONENT =
248             "android.service.dream.DreamService.dream_overlay_component";
249 
250     private final IDreamManager mDreamManager;
251     private final Handler mHandler;
252     private IBinder mDreamToken;
253     private Window mWindow;
254     private Activity mActivity;
255     private boolean mInteractive;
256     private boolean mFullscreen;
257     private boolean mScreenBright = true;
258     private boolean mStarted;
259     private boolean mWaking;
260     private boolean mFinished;
261     private boolean mCanDoze;
262     private boolean mDozing;
263     private boolean mWindowless;
264     private boolean mPreviewMode;
265     private int mDozeScreenState = Display.STATE_UNKNOWN;
266     private @Display.StateReason int mDozeScreenStateReason = Display.STATE_REASON_UNKNOWN;
267     private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
268 
269     private boolean mDebug = false;
270 
271     private ComponentName mDreamComponent;
272     private DreamAccessibility mDreamAccessibility;
273     private boolean mShouldShowComplications;
274 
275     private DreamServiceWrapper mDreamServiceWrapper;
276     private Runnable mDispatchAfterOnAttachedToWindow;
277 
278     private DreamOverlayConnectionHandler mOverlayConnection;
279 
280     private IDreamOverlayCallback mOverlayCallback;
281 
282     private Integer mTrackingConfirmKey = null;
283 
284     private boolean mRedirectWake;
285 
286     private final Injector mInjector;
287 
288     /**
289      * A helper object to inject dependencies into {@link DreamService}.
290      * @hide
291      */
292     @VisibleForTesting
293     public interface Injector {
294         /** Initializes the Injector */
init(Context context)295         void init(Context context);
296 
297         /** Creates and returns the dream overlay connection */
createOverlayConnection(ComponentName overlayComponent)298         DreamOverlayConnectionHandler createOverlayConnection(ComponentName overlayComponent);
299 
300         /** Returns the {@link DreamActivity} component */
getDreamActivityComponent()301         ComponentName getDreamActivityComponent();
302 
303         /** Returns the dream component */
getDreamComponent()304         ComponentName getDreamComponent();
305 
306         /** Returns the dream package name */
getDreamPackageName()307         String getDreamPackageName();
308 
309         /** Returns the {@link DreamManager} */
getDreamManager()310         IDreamManager getDreamManager();
311 
312         /** Returns the associated service info */
getServiceInfo()313         ServiceInfo getServiceInfo();
314 
315         /** Returns the handler to be used for any posted operation */
getHandler()316         Handler getHandler();
317 
318         /** Returns the package manager */
getPackageManager()319         PackageManager getPackageManager();
320 
321         /** Returns the resources */
getResources()322         Resources getResources();
323     }
324 
325     private static final class DefaultInjector implements Injector {
326         private Context mContext;
327         private Class<?> mClassName;
328 
init(Context context)329         public void init(Context context) {
330             mContext = context;
331             mClassName = context.getClass();
332         }
333 
334         @Override
createOverlayConnection( ComponentName overlayComponent)335         public DreamOverlayConnectionHandler createOverlayConnection(
336                 ComponentName overlayComponent) {
337             final Resources resources = mContext.getResources();
338 
339             return new DreamOverlayConnectionHandler(
340                     /* context= */ mContext,
341                     Looper.getMainLooper(),
342                     new Intent().setComponent(overlayComponent),
343                     resources.getInteger(R.integer.config_minDreamOverlayDurationMs),
344                     resources.getInteger(R.integer.config_dreamOverlayMaxReconnectAttempts),
345                     resources.getInteger(R.integer.config_dreamOverlayReconnectTimeoutMs));
346         }
347 
348         @Override
getDreamActivityComponent()349         public ComponentName getDreamActivityComponent() {
350             return new ComponentName(mContext, DreamActivity.class);
351         }
352 
353         @Override
getDreamComponent()354         public ComponentName getDreamComponent() {
355             return new ComponentName(mContext, mClassName);
356         }
357 
358         @Override
getDreamPackageName()359         public String getDreamPackageName() {
360             return mContext.getApplicationContext().getPackageName();
361         }
362 
363         @Override
getDreamManager()364         public IDreamManager getDreamManager() {
365             return IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
366         }
367 
368         @Override
getServiceInfo()369         public ServiceInfo getServiceInfo() {
370             return fetchServiceInfo(mContext, getDreamComponent());
371         }
372 
373         @Override
getHandler()374         public Handler getHandler() {
375             return new Handler(Looper.getMainLooper());
376         }
377 
378         @Override
getPackageManager()379         public PackageManager getPackageManager() {
380             return mContext.getPackageManager();
381         }
382 
383         @Override
getResources()384         public Resources getResources() {
385             return mContext.getResources();
386         }
387 
388     }
389 
DreamService()390     public DreamService() {
391         this(new DefaultInjector());
392     }
393 
394     /**
395      * Constructor for test purposes.
396      *
397      * @param injector used for providing dependencies
398      * @hide
399      */
400     @VisibleForTesting
DreamService(Injector injector)401     public DreamService(Injector injector) {
402         mInjector = injector;
403         mInjector.init(this);
404         mDreamManager = mInjector.getDreamManager();
405         mHandler = mInjector.getHandler();
406     }
407 
408     /**
409      * @hide
410      */
setDebug(boolean dbg)411     public void setDebug(boolean dbg) {
412         mDebug = dbg;
413     }
414 
415     // begin Window.Callback methods
416     /** {@inheritDoc} */
417     @Override
dispatchKeyEvent(KeyEvent event)418     public boolean dispatchKeyEvent(KeyEvent event) {
419         if (dreamHandlesConfirmKeys()) {
420             // In the case of an interactive dream that consumes the event, do not process further.
421             if (mInteractive && mWindow.superDispatchKeyEvent(event)) {
422                 return true;
423             }
424 
425             // If the key is a confirm key and on up, either unlock (no auth) or show bouncer.
426             if (KeyEvent.isConfirmKey(event.getKeyCode())) {
427                 switch (event.getAction()) {
428                     case KeyEvent.ACTION_DOWN -> {
429                         if (mTrackingConfirmKey != null) {
430                             return true;
431                         }
432 
433                         mTrackingConfirmKey = event.getKeyCode();
434                     }
435                     case KeyEvent.ACTION_UP -> {
436                         if (mTrackingConfirmKey == null
437                                 || mTrackingConfirmKey != event.getKeyCode()) {
438                             return true;
439                         }
440 
441                         mTrackingConfirmKey = null;
442 
443                         final KeyguardManager keyguardManager =
444                                 getSystemService(KeyguardManager.class);
445 
446                         // Simply wake up in the case the device is not locked.
447                         if (!keyguardManager.isKeyguardLocked()) {
448                             wakeUp();
449                             return true;
450                         }
451 
452                         keyguardManager.requestDismissKeyguard(getActivity(),
453                                 new KeyguardManager.KeyguardDismissCallback() {
454                                     @Override
455                                     public void onDismissError() {
456                                         Log.e(TAG, "Could not dismiss keyguard on confirm key");
457                                     }
458                                 });
459                     }
460                 }
461 
462                 // All key events for matching key codes should be consumed to prevent other actions
463                 // from triggering.
464                 return true;
465             }
466         }
467 
468         if (!mInteractive) {
469             if (mDebug) Slog.v(mTag, "Waking up on keyEvent");
470             wakeUp();
471             return true;
472         } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
473             if (mDebug) Slog.v(mTag, "Waking up on back key");
474             wakeUp();
475             return true;
476         }
477         return mWindow.superDispatchKeyEvent(event);
478     }
479 
480     /** {@inheritDoc} */
481     @Override
dispatchKeyShortcutEvent(KeyEvent event)482     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
483         if (!mInteractive) {
484             if (mDebug) Slog.v(mTag, "Waking up on keyShortcutEvent");
485             wakeUp();
486             return true;
487         }
488         return mWindow.superDispatchKeyShortcutEvent(event);
489     }
490 
491     /** {@inheritDoc} */
492     @Override
dispatchTouchEvent(MotionEvent event)493     public boolean dispatchTouchEvent(MotionEvent event) {
494         // TODO: create more flexible version of mInteractive that allows clicks
495         // but finish()es on any other kind of activity
496         if (!mInteractive && event.getActionMasked() == MotionEvent.ACTION_UP) {
497             if (mDebug) Slog.v(mTag, "Waking up on touchEvent");
498             wakeUp();
499             return true;
500         }
501         return mWindow.superDispatchTouchEvent(event);
502     }
503 
504     /** {@inheritDoc} */
505     @Override
dispatchTrackballEvent(MotionEvent event)506     public boolean dispatchTrackballEvent(MotionEvent event) {
507         if (!mInteractive) {
508             if (mDebug) Slog.v(mTag, "Waking up on trackballEvent");
509             wakeUp();
510             return true;
511         }
512         return mWindow.superDispatchTrackballEvent(event);
513     }
514 
515     /** {@inheritDoc} */
516     @Override
dispatchGenericMotionEvent(MotionEvent event)517     public boolean dispatchGenericMotionEvent(MotionEvent event) {
518         if (!mInteractive) {
519             if (mDebug) Slog.v(mTag, "Waking up on genericMotionEvent");
520             wakeUp();
521             return true;
522         }
523         return mWindow.superDispatchGenericMotionEvent(event);
524     }
525 
526     /** {@inheritDoc} */
527     @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)528     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
529         return false;
530     }
531 
532     /** {@inheritDoc} */
533     @Override
onCreatePanelView(int featureId)534     public View onCreatePanelView(int featureId) {
535         return null;
536     }
537 
538     /** {@inheritDoc} */
539     @Override
onCreatePanelMenu(int featureId, Menu menu)540     public boolean onCreatePanelMenu(int featureId, Menu menu) {
541         return false;
542     }
543 
544     /** {@inheritDoc} */
545     @Override
onPreparePanel(int featureId, View view, Menu menu)546     public boolean onPreparePanel(int featureId, View view, Menu menu) {
547         return false;
548     }
549 
550     /** {@inheritDoc} */
551     @Override
onMenuOpened(int featureId, Menu menu)552     public boolean onMenuOpened(int featureId, Menu menu) {
553         return false;
554     }
555 
556     /** {@inheritDoc} */
557     @Override
onMenuItemSelected(int featureId, MenuItem item)558     public boolean onMenuItemSelected(int featureId, MenuItem item) {
559         return false;
560     }
561 
562     /** {@inheritDoc} */
563     @Override
onWindowAttributesChanged(LayoutParams attrs)564     public void onWindowAttributesChanged(LayoutParams attrs) {
565     }
566 
567     /** {@inheritDoc} */
568     @Override
onContentChanged()569     public void onContentChanged() {
570     }
571 
572     /** {@inheritDoc} */
573     @Override
onWindowFocusChanged(boolean hasFocus)574     public void onWindowFocusChanged(boolean hasFocus) {
575     }
576 
577     /** {@inheritDoc} */
578     @Override
onAttachedToWindow()579     public void onAttachedToWindow() {
580     }
581 
582     /** {@inheritDoc} */
583     @Override
onDetachedFromWindow()584     public void onDetachedFromWindow() {
585     }
586 
587     /** {@inheritDoc} */
588     @Override
onPanelClosed(int featureId, Menu menu)589     public void onPanelClosed(int featureId, Menu menu) {
590     }
591 
592     /** {@inheritDoc} */
593     @Override
onSearchRequested(SearchEvent event)594     public boolean onSearchRequested(SearchEvent event) {
595         return onSearchRequested();
596     }
597 
598     /** {@inheritDoc} */
599     @Override
onSearchRequested()600     public boolean onSearchRequested() {
601         return false;
602     }
603 
604     /** {@inheritDoc} */
605     @Override
onWindowStartingActionMode(android.view.ActionMode.Callback callback)606     public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) {
607         return null;
608     }
609 
610     /** {@inheritDoc} */
611     @Override
onWindowStartingActionMode( android.view.ActionMode.Callback callback, int type)612     public ActionMode onWindowStartingActionMode(
613             android.view.ActionMode.Callback callback, int type) {
614         return null;
615     }
616 
617     /** {@inheritDoc} */
618     @Override
onActionModeStarted(ActionMode mode)619     public void onActionModeStarted(ActionMode mode) {
620     }
621 
622     /** {@inheritDoc} */
623     @Override
onActionModeFinished(ActionMode mode)624     public void onActionModeFinished(ActionMode mode) {
625     }
626     // end Window.Callback methods
627 
628     // begin public api
629     /**
630      * Retrieves the current {@link android.view.WindowManager} for the dream.
631      * Behaves similarly to {@link android.app.Activity#getWindowManager()}.
632      *
633      * @return The current window manager, or null if the dream is not started.
634      */
getWindowManager()635     public WindowManager getWindowManager() {
636         return mWindow != null ? mWindow.getWindowManager() : null;
637     }
638 
639     /**
640      * Retrieves the current {@link android.view.Window} for the dream.
641      * Behaves similarly to {@link android.app.Activity#getWindow()}.
642      *
643      * @return The current window, or null if the dream is not started.
644      */
getWindow()645     public Window getWindow() {
646         return mWindow;
647     }
648 
649     /**
650      * Retrieves the current {@link android.app.Activity} associated with the dream.
651      * This method behaves similarly to calling {@link android.app.Activity#getActivity()}.
652      *
653      * @return The current activity, or null if the dream is not associated with an activity
654      * or not started.
655      *
656      * @hide
657      */
getActivity()658     public Activity getActivity() {
659         return mActivity;
660     }
661 
662     /**
663      * Inflates a layout resource and set it to be the content view for this Dream.
664      * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
665      *
666      * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
667      *
668      * @param layoutResID Resource ID to be inflated.
669      *
670      * @see #setContentView(android.view.View)
671      * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
672      */
setContentView(@ayoutRes int layoutResID)673     public void setContentView(@LayoutRes int layoutResID) {
674         getWindow().setContentView(layoutResID);
675     }
676 
677     /**
678      * Sets a view to be the content view for this Dream.
679      * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity,
680      * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
681      *
682      * <p>Note: This requires a window, so you should usually call it during
683      * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
684      * during {@link #onCreate}).</p>
685      *
686      * @see #setContentView(int)
687      * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
688      */
setContentView(View view)689     public void setContentView(View view) {
690         getWindow().setContentView(view);
691     }
692 
693     /**
694      * Sets a view to be the content view for this Dream.
695      * Behaves similarly to
696      * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
697      * in an activity.
698      *
699      * <p>Note: This requires a window, so you should usually call it during
700      * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
701      * during {@link #onCreate}).</p>
702      *
703      * @param view The desired content to display.
704      * @param params Layout parameters for the view.
705      *
706      * @see #setContentView(android.view.View)
707      * @see #setContentView(int)
708      */
setContentView(View view, ViewGroup.LayoutParams params)709     public void setContentView(View view, ViewGroup.LayoutParams params) {
710         getWindow().setContentView(view, params);
711     }
712 
713     /**
714      * Adds a view to the Dream's window, leaving other content views in place.
715      *
716      * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
717      *
718      * @param view The desired content to display.
719      * @param params Layout parameters for the view.
720      */
addContentView(View view, ViewGroup.LayoutParams params)721     public void addContentView(View view, ViewGroup.LayoutParams params) {
722         getWindow().addContentView(view, params);
723     }
724 
725     /**
726      * Finds a view that was identified by the id attribute from the XML that
727      * was processed in {@link #onCreate}.
728      *
729      * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
730      * <p>
731      * <strong>Note:</strong> In most cases -- depending on compiler support --
732      * the resulting view is automatically cast to the target class type. If
733      * the target class type is unconstrained, an explicit cast may be
734      * necessary.
735      *
736      * @param id the ID to search for
737      * @return The view if found or null otherwise.
738      * @see View#findViewById(int)
739      * @see DreamService#requireViewById(int)
740      */
741     @Nullable
findViewById(@dRes int id)742     public <T extends View> T findViewById(@IdRes int id) {
743         return getWindow().findViewById(id);
744     }
745 
746     /**
747      * Finds a view that was identified by the id attribute from the XML that was processed in
748      * {@link #onCreate}, or throws an IllegalArgumentException if the ID is invalid or there is no
749      * matching view in the hierarchy.
750      *
751      * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
752      * <p>
753      * <strong>Note:</strong> In most cases -- depending on compiler support --
754      * the resulting view is automatically cast to the target class type. If
755      * the target class type is unconstrained, an explicit cast may be
756      * necessary.
757      *
758      * @param id the ID to search for
759      * @return a view with given ID
760      * @see View#requireViewById(int)
761      * @see DreamService#findViewById(int)
762      */
763     @NonNull
requireViewById(@dRes int id)764     public final <T extends View> T requireViewById(@IdRes int id) {
765         T view = findViewById(id);
766         if (view == null) {
767             throw new IllegalArgumentException(
768                     "ID does not reference a View inside this DreamService");
769         }
770         return view;
771     }
772 
773     /**
774      * Marks this dream as interactive to receive input events.
775      *
776      * <p>Non-interactive dreams (default) will dismiss on the first input event.</p>
777      *
778      * <p>Interactive dreams should call {@link #finish()} to dismiss themselves.</p>
779      *
780      * @param interactive True if this dream will handle input events.
781      */
setInteractive(boolean interactive)782     public void setInteractive(boolean interactive) {
783         mInteractive = interactive;
784         updateAccessibilityMessage();
785     }
786 
787     /**
788      * Returns whether this dream is interactive. Defaults to false.
789      *
790      * @see #setInteractive(boolean)
791      */
isInteractive()792     public boolean isInteractive() {
793         return mInteractive;
794     }
795 
796     /**
797      * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
798      * on the dream's window.
799      *
800      * @param fullscreen If true, the fullscreen flag will be set; else it
801      * will be cleared.
802      */
setFullscreen(boolean fullscreen)803     public void setFullscreen(boolean fullscreen) {
804         if (mFullscreen != fullscreen) {
805             mFullscreen = fullscreen;
806             int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
807             applyWindowFlags(mFullscreen ? flag : 0, flag);
808         }
809     }
810 
811     /**
812      * Returns whether this dream is in fullscreen mode. Defaults to false.
813      *
814      * @see #setFullscreen(boolean)
815      */
isFullscreen()816     public boolean isFullscreen() {
817         return mFullscreen;
818     }
819 
820     /**
821      * Marks this dream as keeping the screen bright while dreaming. In preview mode, the screen
822      * is always allowed to dim and overrides the value specified here.
823      *
824      * @param screenBright True to keep the screen bright while dreaming.
825      */
setScreenBright(boolean screenBright)826     public void setScreenBright(boolean screenBright) {
827         if (mScreenBright != screenBright && !mPreviewMode) {
828             mScreenBright = screenBright;
829             int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
830             applyWindowFlags(mScreenBright ? flag : 0, flag);
831         }
832     }
833 
834     /**
835      * Returns whether this dream keeps the screen bright while dreaming.
836      * Defaults to true, preventing the screen from dimming.
837      *
838      * @see #setScreenBright(boolean)
839      */
isScreenBright()840     public boolean isScreenBright() {
841         return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright);
842     }
843 
844     /**
845      * Marks this dream as windowless. It should be called in {@link #onCreate} method.
846      *
847      * @hide
848      *
849      */
setWindowless(boolean windowless)850     public void setWindowless(boolean windowless) {
851         mWindowless = windowless;
852     }
853 
854     /**
855      * Returns whether this dream is windowless.
856      *
857      * @hide
858      */
isWindowless()859     public boolean isWindowless() {
860         return mWindowless;
861     }
862 
863     /**
864      * Returns true if this dream is allowed to doze.
865      * <p>
866      * The value returned by this method is only meaningful when the dream has started.
867      * </p>
868      *
869      * @return True if this dream can doze.
870      * @see #startDozing
871      * @hide For use by system UI components only.
872      */
873     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
canDoze()874     public boolean canDoze() {
875         return mCanDoze;
876     }
877 
878     /**
879      * Starts dozing, entering a deep dreamy sleep.
880      * <p>
881      * Dozing enables the system to conserve power while the user is not actively interacting
882      * with the device. While dozing, the display will remain on in a low-power state
883      * and will continue to show its previous contents but the application processor and
884      * other system components will be allowed to suspend when possible.
885      * </p><p>
886      * While the application processor is suspended, the dream may stop executing code
887      * for long periods of time. Prior to being suspended, the dream may schedule periodic
888      * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
889      * The dream may also keep the CPU awake by acquiring a
890      * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
891      * Note that since the purpose of doze mode is to conserve power (especially when
892      * running on battery), the dream should not wake the CPU very often or keep it
893      * awake for very long.
894      * </p><p>
895      * It is a good idea to call this method some time after the dream's entry animation
896      * has completed and the dream is ready to doze. It is important to completely
897      * finish all of the work needed before dozing since the application processor may
898      * be suspended at any moment once this method is called unless other wake locks
899      * are being held.
900      * </p><p>
901      * Call {@link #stopDozing} or {@link #finish} to stop dozing.
902      * </p>
903      *
904      * @see #stopDozing
905      * @hide For use by system UI components only.
906      */
907     @UnsupportedAppUsage
startDozing()908     public void startDozing() {
909         synchronized (this) {
910             if (mCanDoze && !mDozing) {
911                 mDozing = true;
912                 updateDoze();
913             }
914         }
915     }
916 
updateDoze()917     private synchronized void updateDoze() {
918         if (mDreamToken == null) {
919             Slog.w(mTag, "Updating doze without a dream token.");
920             return;
921         }
922 
923         if (mDozing) {
924             try {
925                 Slog.v(mTag, "UpdateDoze mDozeScreenState=" + mDozeScreenState
926                         + " mDozeScreenBrightness=" + mDozeScreenBrightness);
927                 mDreamManager.startDozing(
928                         mDreamToken, mDozeScreenState, mDozeScreenStateReason,
929                         mDozeScreenBrightness);
930             } catch (RemoteException ex) {
931                 // system server died
932             }
933         }
934     }
935 
936     /**
937      * Stops dozing, returns to active dreaming.
938      * <p>
939      * This method reverses the effect of {@link #startDozing}. From this moment onward,
940      * the application processor will be kept awake as long as the dream is running
941      * or until the dream starts dozing again.
942      * </p>
943      *
944      * @see #startDozing
945      * @hide For use by system UI components only.
946      */
947     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
stopDozing()948     public void stopDozing() {
949         if (mDozing) {
950             mDozing = false;
951             try {
952                 mDreamManager.stopDozing(mDreamToken);
953             } catch (RemoteException ex) {
954                 // system server died
955             }
956         }
957     }
958 
959     /**
960      * Returns true if the dream will allow the system to enter a low-power state while
961      * it is running without actually turning off the screen. Defaults to false,
962      * keeping the application processor awake while the dream is running.
963      *
964      * @return True if the dream is dozing.
965      *
966      * @hide For use by system UI components only.
967      */
968     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isDozing()969     public boolean isDozing() {
970         return mDozing;
971     }
972 
973     /**
974      * Gets the screen state to use while dozing.
975      *
976      * @return The screen state to use while dozing, such as {@link Display#STATE_ON},
977      * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
978      * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
979      * for the default behavior.
980      *
981      * @see #setDozeScreenState
982      * @hide For use by system UI components only.
983      */
getDozeScreenState()984     public int getDozeScreenState() {
985         return mDozeScreenState;
986     }
987 
988     /**
989      * Same as {@link #setDozeScreenState(int, int)}, but with no screen state reason specified.
990      *
991      * <p>Use {@link #setDozeScreenState(int, int)} whenever possible to allow properly accounting
992      * for the screen state reason.
993      *
994      * @hide
995      */
996     @UnsupportedAppUsage
setDozeScreenState(int state)997     public void setDozeScreenState(int state) {
998         setDozeScreenState(state, Display.STATE_REASON_UNKNOWN);
999     }
1000 
1001     /**
1002      * Sets the screen state to use while dozing.
1003      * <p>
1004      * The value of this property determines the power state of the primary display
1005      * once {@link #startDozing} has been called. The default value is
1006      * {@link Display#STATE_UNKNOWN} which lets the system decide.
1007      * The dream may set a different state before starting to doze and may
1008      * perform transitions between states while dozing to conserve power and
1009      * achieve various effects.
1010      * </p><p>
1011      * Some devices will have dedicated hardware ("Sidekick") to animate
1012      * the display content while the CPU sleeps. If the dream and the hardware support
1013      * this, {@link Display#STATE_ON_SUSPEND} or {@link Display#STATE_DOZE_SUSPEND}
1014      * will switch control to the Sidekick.
1015      * </p><p>
1016      * If not using Sidekick, it is recommended that the state be set to
1017      * {@link Display#STATE_DOZE_SUSPEND} once the dream has completely
1018      * finished drawing and before it releases its wakelock
1019      * to allow the display hardware to be fully suspended. While suspended,
1020      * the display will preserve its on-screen contents.
1021      * </p><p>
1022      * If the doze suspend state is used, the dream must make sure to set the mode back
1023      * to {@link Display#STATE_DOZE} or {@link Display#STATE_ON} before drawing again
1024      * since the display updates may be ignored and not seen by the user otherwise.
1025      * </p><p>
1026      * The set of available display power states and their behavior while dozing is
1027      * hardware dependent and may vary across devices. The dream may therefore
1028      * need to be modified or configured to correctly support the hardware.
1029      * </p>
1030      *
1031      * @param state The screen state to use while dozing, such as {@link Display#STATE_ON},
1032      * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
1033      * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
1034      * for the default behavior.
1035      * @param reason the reason for setting the specified screen state.
1036      *
1037      * @hide For use by system UI components only.
1038      */
1039     @UnsupportedAppUsage
setDozeScreenState(int state, @Display.StateReason int reason)1040     public void setDozeScreenState(int state, @Display.StateReason int reason) {
1041         synchronized (this) {
1042             if (mDozeScreenState != state) {
1043                 mDozeScreenState = state;
1044                 mDozeScreenStateReason = reason;
1045                 updateDoze();
1046             }
1047         }
1048     }
1049 
1050     /**
1051      * Gets the screen brightness to use while dozing.
1052      *
1053      * @return The screen brightness while dozing as a value between
1054      * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
1055      * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
1056      * its default policy based on the screen state.
1057      *
1058      * @see #setDozeScreenBrightness
1059      * @hide For use by system UI components only.
1060      */
1061     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getDozeScreenBrightness()1062     public int getDozeScreenBrightness() {
1063         return mDozeScreenBrightness;
1064     }
1065 
1066     /**
1067      * Sets the screen brightness to use while dozing.
1068      * <p>
1069      * The value of this property determines the power state of the primary display
1070      * once {@link #startDozing} has been called. The default value is
1071      * {@link PowerManager#BRIGHTNESS_DEFAULT} which lets the system decide.
1072      * The dream may set a different brightness before starting to doze and may adjust
1073      * the brightness while dozing to conserve power and achieve various effects.
1074      * </p><p>
1075      * Note that dream may specify any brightness in the full 0-255 range, including
1076      * values that are less than the minimum value for manual screen brightness
1077      * adjustments by the user. In particular, the value may be set to 0 which may
1078      * turn off the backlight entirely while still leaving the screen on although
1079      * this behavior is device dependent and not guaranteed.
1080      * </p><p>
1081      * The available range of display brightness values and their behavior while dozing is
1082      * hardware dependent and may vary across devices. The dream may therefore
1083      * need to be modified or configured to correctly support the hardware.
1084      * </p>
1085      *
1086      * @param brightness The screen brightness while dozing as a value between
1087      * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
1088      * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
1089      * its default policy based on the screen state.
1090      *
1091      * @hide For use by system UI components only.
1092      */
1093     @UnsupportedAppUsage
setDozeScreenBrightness(int brightness)1094     public void setDozeScreenBrightness(int brightness) {
1095         if (brightness != PowerManager.BRIGHTNESS_DEFAULT) {
1096             brightness = clampAbsoluteBrightness(brightness);
1097         }
1098         synchronized (this) {
1099             if (mDozeScreenBrightness != brightness) {
1100                 mDozeScreenBrightness = brightness;
1101                 updateDoze();
1102             }
1103         }
1104     }
1105 
1106     /**
1107      * Called when this Dream is constructed.
1108      */
1109     @Override
onCreate()1110     public void onCreate() {
1111         if (mDebug) Slog.v(mTag, "onCreate()");
1112 
1113         mDreamComponent = mInjector.getDreamComponent();
1114         mShouldShowComplications = fetchShouldShowComplications(mInjector.getPackageManager(),
1115                 mInjector.getServiceInfo());
1116         mOverlayCallback = new IDreamOverlayCallback.Stub() {
1117             @Override
1118             public void onExitRequested() {
1119                 // Simply finish dream when exit is requested.
1120                 mHandler.post(() -> finish());
1121             }
1122 
1123             @Override
1124             public void onRedirectWake(boolean redirect) {
1125                 mRedirectWake = redirect;
1126             }
1127         };
1128 
1129         super.onCreate();
1130     }
1131 
1132     /**
1133      * Called when the dream's window has been created and is visible and animation may now begin.
1134      */
onDreamingStarted()1135     public void onDreamingStarted() {
1136         if (mDebug) Slog.v(mTag, "onDreamingStarted()");
1137         // hook for subclasses
1138     }
1139 
1140     /**
1141      * Called when this Dream is stopped, either by external request or by calling finish(),
1142      * before the window has been removed.
1143      */
onDreamingStopped()1144     public void onDreamingStopped() {
1145         if (mDebug) Slog.v(mTag, "onDreamingStopped()");
1146         // hook for subclasses
1147     }
1148 
1149     /**
1150      * Called when the dream is being asked to stop itself and wake.
1151      * <p>
1152      * The default implementation simply calls {@link #finish} which ends the dream
1153      * immediately. Subclasses may override this function to perform a smooth exit
1154      * transition then call {@link #finish} afterwards.
1155      * </p><p>
1156      * Note that the dream will only be given a short period of time (currently about
1157      * five seconds) to wake up. If the dream does not finish itself in a timely manner
1158      * then the system will forcibly finish it once the time allowance is up.
1159      * </p>
1160      */
onWakeUp()1161     public void onWakeUp() {
1162         if (mOverlayConnection != null) {
1163             mOverlayConnection.addConsumer(overlay -> {
1164                 try {
1165                     overlay.wakeUp();
1166                 } catch (RemoteException e) {
1167                     Slog.e(TAG, "Error waking the overlay service", e);
1168                 } finally {
1169                     finish();
1170                 }
1171             });
1172         } else {
1173             finish();
1174         }
1175     }
1176 
1177     /** {@inheritDoc} */
1178     @Override
onBind(Intent intent)1179     public final IBinder onBind(Intent intent) {
1180         if (mDebug) Slog.v(mTag, "onBind() intent = " + intent);
1181         mDreamServiceWrapper = new DreamServiceWrapper();
1182         final ComponentName overlayComponent = intent.getParcelableExtra(
1183                 EXTRA_DREAM_OVERLAY_COMPONENT, ComponentName.class);
1184 
1185         // Connect to the overlay service if present.
1186         if (!mWindowless && overlayComponent != null) {
1187             mOverlayConnection = mInjector.createOverlayConnection(overlayComponent);
1188 
1189             if (!mOverlayConnection.bind()) {
1190                 // Binding failed.
1191                 mOverlayConnection = null;
1192             }
1193         }
1194 
1195         return mDreamServiceWrapper;
1196     }
1197 
1198     @Override
onUnbind(Intent intent)1199     public boolean onUnbind(Intent intent) {
1200         // We must unbind from any overlay connection if we are unbound before finishing.
1201         if (mOverlayConnection != null) {
1202             mOverlayConnection.unbind();
1203             mOverlayConnection = null;
1204         }
1205 
1206         return super.onUnbind(intent);
1207     }
1208 
1209     /**
1210      * Stops the dream and detaches from the window.
1211      * <p>
1212      * When the dream ends, the system will be allowed to go to sleep fully unless there
1213      * is a reason for it to be awake such as recent user activity or wake locks being held.
1214      * </p>
1215      */
finish()1216     public final void finish() {
1217         // If there is an active overlay connection, signal that the dream is ending before
1218         // continuing. Note that the overlay cannot rely on the unbound state, since another dream
1219         // might have bound to it in the meantime.
1220         if (mOverlayConnection != null) {
1221             mOverlayConnection.addConsumer(overlay -> {
1222                 try {
1223                     overlay.endDream();
1224                     mOverlayConnection.unbind();
1225                     mOverlayConnection = null;
1226                 } catch (RemoteException e) {
1227                     Log.e(mTag, "could not inform overlay of dream end:" + e);
1228                 }
1229             });
1230         }
1231 
1232         if (mDebug) Slog.v(mTag, "finish(): mFinished=" + mFinished);
1233 
1234         Activity activity = mActivity;
1235         if (activity != null) {
1236             if (!activity.isFinishing()) {
1237                 // In case the activity is not finished yet, do it now.
1238                 activity.finishAndRemoveTask();
1239             }
1240             return;
1241         }
1242 
1243         if (mFinished) {
1244             return;
1245         }
1246         mFinished = true;
1247 
1248         if (mDreamToken == null) {
1249             if (mDebug) Slog.v(mTag, "finish() called when not attached.");
1250             stopSelf();
1251             return;
1252         }
1253 
1254         try {
1255             // finishSelf will unbind the dream controller from the dream service. This will
1256             // trigger DreamService.this.onDestroy and DreamService.this will die.
1257             mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
1258         } catch (RemoteException ex) {
1259             // system server died
1260         }
1261     }
1262 
1263     /**
1264      * Wakes the dream up gently.
1265      * <p>
1266      * Calls {@link #onWakeUp} to give the dream a chance to perform an exit transition.
1267      * When the transition is over, the dream should call {@link #finish}.
1268      * </p>
1269      */
wakeUp()1270     public final void wakeUp() {
1271         wakeUp(false);
1272     }
1273 
1274     /**
1275      * Tells the dream to come to the front (which in turn tells the overlay to come to the front).
1276      */
comeToFront()1277     private void comeToFront() {
1278         mOverlayConnection.addConsumer(overlay -> {
1279             try {
1280                 overlay.comeToFront();
1281             } catch (RemoteException e) {
1282                 Log.e(mTag, "could not tell overlay to come to front:" + e);
1283             }
1284         });
1285     }
1286 
1287     /**
1288      * Whether or not wake requests will be redirected.
1289      *
1290      * @hide
1291      */
getRedirectWake()1292     public boolean getRedirectWake() {
1293         return mOverlayConnection != null && mRedirectWake;
1294     }
1295 
wakeUp(boolean fromSystem)1296     private void wakeUp(boolean fromSystem) {
1297         if (mDebug) {
1298             Slog.v(mTag, "wakeUp(): fromSystem=" + fromSystem + ", mWaking=" + mWaking
1299                     + ", mFinished=" + mFinished);
1300         }
1301 
1302         if (!fromSystem && getRedirectWake()) {
1303             mOverlayConnection.addConsumer(overlay -> {
1304                 try {
1305                     overlay.onWakeRequested();
1306                 } catch (RemoteException e) {
1307                     Log.e(mTag, "could not inform overlay of dream wakeup:" + e);
1308                 }
1309             });
1310 
1311             return;
1312         }
1313 
1314         if (!mWaking && !mFinished) {
1315             mWaking = true;
1316 
1317             if (mActivity != null) {
1318                 // During wake up the activity should be translucent to allow the application
1319                 // underneath to start drawing. Normally, the WM animation system takes care of
1320                 // this, but here we give the dream application some time to perform a custom exit
1321                 // animation. If it uses a view animation, the WM doesn't know about it and can't
1322                 // make the activity translucent in the normal way. Therefore, here we ensure that
1323                 // the activity is translucent during wake up regardless of what animation is used
1324                 // in onWakeUp().
1325                 mActivity.convertToTranslucent(null, null);
1326             }
1327 
1328             // As a minor optimization, invoke the callback first in case it simply
1329             // calls finish() immediately so there wouldn't be much point in telling
1330             // the system that we are finishing the dream gently.
1331             onWakeUp();
1332 
1333             // Now tell the system we are waking gently, unless we already told
1334             // it we were finishing immediately.
1335             if (!fromSystem && !mFinished) {
1336                 if (mActivity == null) {
1337                     Slog.w(mTag, "WakeUp was called before the dream was attached.");
1338                 } else {
1339                     try {
1340                         mDreamManager.finishSelf(mDreamToken, false /*immediate*/);
1341                     } catch (RemoteException ex) {
1342                         // system server died
1343                     }
1344                 }
1345             }
1346         }
1347     }
1348 
1349     /** {@inheritDoc} */
1350     @Override
onDestroy()1351     public void onDestroy() {
1352         if (mDebug) Slog.v(mTag, "onDestroy()");
1353         // hook for subclasses
1354 
1355         // Just in case destroy came in before detach, let's take care of that now
1356         detach();
1357         mOverlayCallback = null;
1358         super.onDestroy();
1359     }
1360 
1361     // end public api
1362 
1363     /**
1364      * Parses and returns metadata of the dream service indicated by the service info. Returns null
1365      * if metadata cannot be found.
1366      *
1367      * Note that {@link ServiceInfo} must be fetched with {@link PackageManager#GET_META_DATA} flag.
1368      *
1369      * @hide
1370      */
1371     @Nullable
1372     @TestApi
getDreamMetadata(@onNull Context context, @Nullable ServiceInfo serviceInfo)1373     public static DreamMetadata getDreamMetadata(@NonNull Context context,
1374             @Nullable ServiceInfo serviceInfo) {
1375         return getDreamMetadata(context.getPackageManager(), serviceInfo);
1376     }
1377 
1378     /**
1379      * Parses and returns metadata of the dream service indicated by the service info. Returns null
1380      * if metadata cannot be found.
1381      *
1382      * Note that {@link ServiceInfo} must be fetched with {@link PackageManager#GET_META_DATA} flag.
1383      *
1384      * @hide
1385      */
1386     @Nullable
getDreamMetadata(@onNull PackageManager packageManager, @Nullable ServiceInfo serviceInfo)1387     public static DreamMetadata getDreamMetadata(@NonNull PackageManager packageManager,
1388             @Nullable ServiceInfo serviceInfo) {
1389         if (serviceInfo == null) return null;
1390 
1391         try (TypedArray rawMetadata = packageManager.extractPackageItemInfoAttributes(serviceInfo,
1392                 DreamService.DREAM_META_DATA, DREAM_META_DATA_ROOT_TAG,
1393                 com.android.internal.R.styleable.Dream)) {
1394             if (rawMetadata == null) return null;
1395             try {
1396                 return new DreamMetadata(
1397                         convertToComponentName(
1398                                 rawMetadata.getString(
1399                                         com.android.internal.R.styleable.Dream_settingsActivity),
1400                                 serviceInfo),
1401                         rawMetadata.getDrawable(
1402                                 com.android.internal.R.styleable.Dream_previewImage),
1403                         rawMetadata.getBoolean(R.styleable.Dream_showClockAndComplications,
1404                                 DEFAULT_SHOW_COMPLICATIONS),
1405                         rawMetadata.getInt(R.styleable.Dream_dreamCategory, DREAM_CATEGORY_DEFAULT)
1406                 );
1407             } catch (Exception exception) {
1408                 Log.e(TAG, "Failed to create read metadata", exception);
1409                 return null;
1410             }
1411         }
1412     }
1413 
1414     @Nullable
convertToComponentName(@ullable String flattenedString, ServiceInfo serviceInfo)1415     private static ComponentName convertToComponentName(@Nullable String flattenedString,
1416             ServiceInfo serviceInfo) {
1417         if (flattenedString == null) {
1418             return null;
1419         }
1420 
1421         if (!flattenedString.contains("/")) {
1422             return new ComponentName(serviceInfo.packageName, flattenedString);
1423         }
1424 
1425         // Ensure that the component is from the same package as the dream service. If not,
1426         // treat the component as invalid and return null instead.
1427         final ComponentName cn = ComponentName.unflattenFromString(flattenedString);
1428         if (cn == null) return null;
1429         if (!cn.getPackageName().equals(serviceInfo.packageName)) {
1430             Log.w(TAG,
1431                     "Inconsistent package name in component: " + cn.getPackageName()
1432                             + ", should be: " + serviceInfo.packageName);
1433             return null;
1434         }
1435         return cn;
1436     }
1437 
1438     /**
1439      * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
1440      *
1441      * Must run on mHandler.
1442      */
detach()1443     private void detach() {
1444         if (mStarted) {
1445             if (mDebug) Slog.v(mTag, "detach(): Calling onDreamingStopped()");
1446             mStarted = false;
1447             onDreamingStopped();
1448         }
1449 
1450         if (mActivity != null && !mActivity.isFinishing()) {
1451             mActivity.finishAndRemoveTask();
1452         } else {
1453             finish();
1454         }
1455 
1456         mDreamToken = null;
1457         mCanDoze = false;
1458     }
1459 
1460     /**
1461      * Called when the Dream is ready to be shown.
1462      *
1463      * Must run on mHandler.
1464      *
1465      * @param dreamToken Token for this dream service.
1466      * @param started    A callback that will be invoked once onDreamingStarted has completed.
1467      */
attach(IBinder dreamToken, boolean canDoze, boolean isPreviewMode, IRemoteCallback started)1468     private void attach(IBinder dreamToken, boolean canDoze, boolean isPreviewMode,
1469             IRemoteCallback started) {
1470         if (mDreamToken != null) {
1471             Slog.e(mTag, "attach() called when dream with token=" + mDreamToken
1472                     + " already attached");
1473             return;
1474         }
1475         if (mFinished || mWaking) {
1476             Slog.w(mTag, "attach() called after dream already finished");
1477             try {
1478                 mDreamManager.finishSelf(dreamToken, true /*immediate*/);
1479             } catch (RemoteException ex) {
1480                 // system server died
1481             }
1482             return;
1483         }
1484 
1485         mDreamToken = dreamToken;
1486         mCanDoze = canDoze;
1487         mPreviewMode = isPreviewMode;
1488         if (mPreviewMode) {
1489             // Allow screen to dim when in preview mode.
1490             mScreenBright = false;
1491         }
1492         // This is not a security check to prevent malicious dreams but a guard rail to stop
1493         // third-party dreams from being windowless and not working well as a result.
1494         if (mWindowless && !mCanDoze && !isCallerSystemUi()) {
1495             throw new IllegalStateException("Only doze or SystemUI dreams can be windowless.");
1496         }
1497 
1498         mDispatchAfterOnAttachedToWindow = () -> {
1499             if (mWindow != null || mWindowless) {
1500                 mStarted = true;
1501                 try {
1502                     onDreamingStarted();
1503                 } finally {
1504                     try {
1505                         started.sendResult(null);
1506                     } catch (RemoteException e) {
1507                         throw e.rethrowFromSystemServer();
1508                     }
1509                 }
1510             }
1511         };
1512 
1513         // We need to defer calling onDreamingStarted until after the activity is created.
1514         // If the dream is windowless, we can call it immediately. Otherwise, we wait
1515         // for the DreamActivity to report onActivityCreated via
1516         // DreamServiceWrapper.onActivityCreated.
1517         if (!mWindowless) {
1518             Intent i = new Intent();
1519             i.setComponent(mInjector.getDreamActivityComponent());
1520             i.setPackage(mInjector.getDreamPackageName());
1521             i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
1522             DreamActivity.setCallback(i, new DreamActivityCallbacks(mDreamToken));
1523             final ServiceInfo serviceInfo = mInjector.getServiceInfo();
1524             final CharSequence title = fetchDreamLabel(mInjector.getPackageManager(),
1525                     mInjector.getResources(), serviceInfo, isPreviewMode);
1526 
1527             DreamActivity.setTitle(i, title);
1528 
1529             try {
1530                 mDreamManager.startDreamActivity(i);
1531             } catch (SecurityException e) {
1532                 Log.w(mTag,
1533                         "Received SecurityException trying to start DreamActivity. "
1534                         + "Aborting dream start.");
1535                 detach();
1536             } catch (RemoteException e) {
1537                 Log.w(mTag, "Could not connect to activity task manager to start dream activity");
1538                 e.rethrowFromSystemServer();
1539             }
1540         } else {
1541             mDispatchAfterOnAttachedToWindow.run();
1542         }
1543     }
1544 
onWindowCreated(Window w)1545     private void onWindowCreated(Window w) {
1546         mWindow = w;
1547         mWindow.setCallback(this);
1548         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
1549 
1550         WindowManager.LayoutParams lp = mWindow.getAttributes();
1551         lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
1552                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
1553                     | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
1554                     | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
1555                     | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
1556                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
1557                     | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
1558                     | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
1559                     );
1560         lp.layoutInDisplayCutoutMode =
1561                 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
1562         mWindow.setAttributes(lp);
1563         // Workaround: Currently low-profile and in-window system bar backgrounds don't go
1564         // along well. Dreams usually don't need such bars anyways, so disable them by default.
1565         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
1566 
1567         // Hide all insets when the dream is showing
1568         mWindow.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
1569         mWindow.setDecorFitsSystemWindows(false);
1570         updateAccessibilityMessage();
1571         mWindow.getDecorView().addOnAttachStateChangeListener(
1572                 new View.OnAttachStateChangeListener() {
1573                     private Consumer<IDreamOverlayClient> mDreamStartOverlayConsumer;
1574 
1575                     @Override
1576                     public void onViewAttachedToWindow(View v) {
1577                         mDispatchAfterOnAttachedToWindow.run();
1578 
1579                         if (mOverlayConnection != null) {
1580                             // Request the DreamOverlay be told to dream with dream's window
1581                             // parameters once the window has been attached.
1582                             mDreamStartOverlayConsumer = overlay -> {
1583                                 if (mWindow == null) {
1584                                     Slog.d(TAG, "mWindow is null");
1585                                     return;
1586                                 }
1587                                 try {
1588                                     overlay.startDream(mWindow.getAttributes(), mOverlayCallback,
1589                                             mDreamComponent.flattenToString(),
1590                                             mShouldShowComplications);
1591                                 } catch (RemoteException e) {
1592                                     Log.e(mTag, "could not send window attributes:" + e);
1593                                 }
1594                             };
1595                             mOverlayConnection.addConsumer(mDreamStartOverlayConsumer);
1596                         }
1597                     }
1598 
1599                     @Override
1600                     public void onViewDetachedFromWindow(View v) {
1601                         if (mActivity == null || !mActivity.isChangingConfigurations()) {
1602                             // Only stop the dream if the view is not detached by relaunching
1603                             // activity for configuration changes. It is important to also clear
1604                             // the window reference in order to fully release the DreamActivity.
1605                             mWindow = null;
1606                             mActivity = null;
1607                             finish();
1608                         }
1609 
1610                         if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) {
1611                             mOverlayConnection.removeConsumer(mDreamStartOverlayConsumer);
1612                         }
1613                     }
1614                 });
1615     }
1616 
updateAccessibilityMessage()1617     private void updateAccessibilityMessage() {
1618         if (mWindow == null) return;
1619         if (mDreamAccessibility == null) {
1620             final View rootView = mWindow.getDecorView();
1621             mDreamAccessibility = new DreamAccessibility(this, rootView);
1622         }
1623         mDreamAccessibility.updateAccessibilityConfiguration(isInteractive());
1624     }
1625 
getWindowFlagValue(int flag, boolean defaultValue)1626     private boolean getWindowFlagValue(int flag, boolean defaultValue) {
1627         return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0;
1628     }
1629 
applyWindowFlags(int flags, int mask)1630     private void applyWindowFlags(int flags, int mask) {
1631         if (mWindow != null) {
1632             WindowManager.LayoutParams lp = mWindow.getAttributes();
1633             lp.flags = applyFlags(lp.flags, flags, mask);
1634             mWindow.setAttributes(lp);
1635             mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
1636         }
1637     }
1638 
isCallerSystemUi()1639     private boolean isCallerSystemUi() {
1640         return checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
1641                 == PERMISSION_GRANTED;
1642     }
1643 
applyFlags(int oldFlags, int flags, int mask)1644     private int applyFlags(int oldFlags, int flags, int mask) {
1645         return (oldFlags&~mask) | (flags&mask);
1646     }
1647 
1648     /**
1649      * Fetches metadata of the dream indicated by the {@link ComponentName}, and returns whether
1650      * the dream should show complications on the overlay. If not defined, returns
1651      * {@link DreamService#DEFAULT_SHOW_COMPLICATIONS}.
1652      */
fetchShouldShowComplications(@onNull PackageManager packageManager, @Nullable ServiceInfo serviceInfo)1653     private static boolean fetchShouldShowComplications(@NonNull PackageManager packageManager,
1654             @Nullable ServiceInfo serviceInfo) {
1655         final DreamMetadata metadata = getDreamMetadata(packageManager, serviceInfo);
1656         if (metadata != null) {
1657             return metadata.showComplications;
1658         }
1659         return DEFAULT_SHOW_COMPLICATIONS;
1660     }
1661 
1662     @Nullable
fetchDreamLabel( PackageManager pm, Resources resources, @Nullable ServiceInfo serviceInfo, boolean isPreviewMode)1663     private static CharSequence fetchDreamLabel(
1664             PackageManager pm,
1665             Resources resources,
1666             @Nullable ServiceInfo serviceInfo,
1667             boolean isPreviewMode) {
1668         if (serviceInfo == null) {
1669             return null;
1670         }
1671         final CharSequence dreamLabel = serviceInfo.loadLabel(pm);
1672         if (!isPreviewMode || dreamLabel == null) {
1673             return dreamLabel;
1674         }
1675         // When in preview mode, return a special label indicating the dream is in preview.
1676         return resources.getString(R.string.dream_preview_title, dreamLabel);
1677     }
1678 
1679     @Nullable
fetchServiceInfo(Context context, ComponentName componentName)1680     private static ServiceInfo fetchServiceInfo(Context context, ComponentName componentName) {
1681         final PackageManager pm = context.getPackageManager();
1682 
1683         try {
1684             return pm.getServiceInfo(componentName,
1685                     PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
1686         } catch (PackageManager.NameNotFoundException e) {
1687             if (DEBUG) Log.w(TAG, "cannot find component " + componentName.flattenToShortString());
1688         }
1689         return null;
1690     }
1691 
1692     @Override
dump(final FileDescriptor fd, PrintWriter pw, final String[] args)1693     protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) {
1694         DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> dumpOnHandler(fd, pw1, args), pw, "", 1000);
1695     }
1696 
1697     /** @hide */
dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args)1698     protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
1699         pw.print(mTag + ": ");
1700         if (mFinished) {
1701             pw.println("stopped");
1702         } else {
1703             pw.println("running (dreamToken=" + mDreamToken + ")");
1704         }
1705         pw.println("  window: " + mWindow);
1706         pw.print("  flags:");
1707         if (isInteractive()) pw.print(" interactive");
1708         if (isFullscreen()) pw.print(" fullscreen");
1709         if (isScreenBright()) pw.print(" bright");
1710         if (isWindowless()) pw.print(" windowless");
1711         if (isDozing()) pw.print(" dozing");
1712         else if (canDoze()) pw.print(" candoze");
1713         pw.println();
1714         if (canDoze()) {
1715             pw.println("  doze screen state: " + Display.stateToString(mDozeScreenState));
1716             pw.println("  doze screen brightness: " + mDozeScreenBrightness);
1717         }
1718     }
1719 
clampAbsoluteBrightness(int value)1720     private static int clampAbsoluteBrightness(int value) {
1721         return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1722     }
1723 
1724     /**
1725      * The DreamServiceWrapper is used as a gateway to the system_server, where DreamController
1726      * uses it to control the DreamService. It is also used to receive callbacks from the
1727      * DreamActivity.
1728      */
1729     final class DreamServiceWrapper extends IDreamService.Stub {
1730         @Override
attach(final IBinder dreamToken, final boolean canDoze, final boolean isPreviewMode, IRemoteCallback started)1731         public void attach(final IBinder dreamToken, final boolean canDoze,
1732                 final boolean isPreviewMode, IRemoteCallback started) {
1733             mHandler.post(
1734                     () -> DreamService.this.attach(dreamToken, canDoze, isPreviewMode, started));
1735         }
1736 
1737         @Override
detach()1738         public void detach() {
1739             mHandler.post(DreamService.this::detach);
1740         }
1741 
1742         @Override
wakeUp()1743         public void wakeUp() {
1744             mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
1745         }
1746 
1747         @Override
comeToFront()1748         public void comeToFront() {
1749             if (!dreamHandlesBeingObscured()) {
1750                 return;
1751             }
1752 
1753             mHandler.post(DreamService.this::comeToFront);
1754         }
1755     }
1756 
1757     /** @hide */
1758     @VisibleForTesting
1759     public final class DreamActivityCallbacks extends Binder {
1760         private final IBinder mActivityDreamToken;
1761 
DreamActivityCallbacks(IBinder token)1762         DreamActivityCallbacks(IBinder token) {
1763             mActivityDreamToken = token;
1764         }
1765 
1766         /** Callback when the {@link DreamActivity} has been created */
onActivityCreated(DreamActivity activity)1767         public void onActivityCreated(DreamActivity activity) {
1768             if (mActivityDreamToken != mDreamToken || mFinished) {
1769                 Slog.d(TAG, "DreamActivity was created after the dream was finished or "
1770                         + "a new dream started, finishing DreamActivity");
1771                 if (!activity.isFinishing()) {
1772                     activity.finishAndRemoveTask();
1773                 }
1774                 return;
1775             }
1776             if (mActivity != null) {
1777                 Slog.w(TAG, "A DreamActivity has already been started, "
1778                         + "finishing latest DreamActivity");
1779                 if (!activity.isFinishing()) {
1780                     activity.finishAndRemoveTask();
1781                 }
1782                 return;
1783             }
1784 
1785             mActivity = activity;
1786             onWindowCreated(activity.getWindow());
1787         }
1788 
1789         /** Callback when the {@link DreamActivity} has been destroyed */
onActivityDestroyed()1790         public void onActivityDestroyed() {
1791             mActivity = null;
1792             mWindow = null;
1793             detach();
1794         }
1795     }
1796 
1797     /**
1798      * Represents metadata defined in {@link android.R.styleable#Dream &lt;dream&gt;}.
1799      *
1800      * @hide
1801      */
1802     @VisibleForTesting
1803     @TestApi
1804     public static final class DreamMetadata {
1805         @Nullable
1806         public final ComponentName settingsActivity;
1807 
1808         @Nullable
1809         public final Drawable previewImage;
1810 
1811         @NonNull
1812         public final boolean showComplications;
1813 
1814         @NonNull
1815         @FlaggedApi(Flags.FLAG_HOME_PANEL_DREAM)
1816         public final int dreamCategory;
1817 
1818         /**
1819          * @hide
1820          */
1821         @VisibleForTesting
DreamMetadata( ComponentName settingsActivity, Drawable previewImage, boolean showComplications, int dreamCategory)1822         public DreamMetadata(
1823                 ComponentName settingsActivity,
1824                 Drawable previewImage,
1825                 boolean showComplications,
1826                 int dreamCategory) {
1827             this.settingsActivity = settingsActivity;
1828             this.previewImage = previewImage;
1829             this.showComplications = showComplications;
1830             if (Flags.homePanelDream()) {
1831                 this.dreamCategory = dreamCategory;
1832             } else {
1833                 this.dreamCategory = DREAM_CATEGORY_DEFAULT;
1834             }
1835         }
1836     }
1837 
1838     /**
1839      * Sets the dream overlay component to be used by the dream.
1840      *
1841      * @hide
1842      */
1843     @VisibleForTesting
setDreamOverlayComponent(Intent intent, ComponentName component)1844     public static void setDreamOverlayComponent(Intent intent, ComponentName component) {
1845         intent.putExtra(DreamService.EXTRA_DREAM_OVERLAY_COMPONENT, component);
1846     }
1847 }
1848