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