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