blob: 337027ef5bc99cfbf1add65df8dc2ead8c5545a2 [file] [log] [blame]
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001/**
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 */
16package android.service.dreams;
17
Tor Norbye7b9c9122013-05-30 16:48:33 -070018import android.annotation.IdRes;
19import android.annotation.LayoutRes;
Chris Craik6faa9e52018-01-11 10:46:10 -080020import android.annotation.NonNull;
Scott Kennedyc0519552015-02-11 15:33:10 -080021import android.annotation.Nullable;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Galia Peycheva6861e912019-08-21 10:20:23 +020024import android.app.Activity;
25import android.app.ActivityTaskManager;
Jeff Brown26875502014-01-30 21:47:47 -080026import android.app.AlarmManager;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070027import android.app.Service;
Artur Satayevdf439592019-12-10 17:47:53 +000028import android.compat.annotation.UnsupportedAppUsage;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070029import android.content.Intent;
Mathew Inwood8c854f82018-09-14 12:35:36 +010030import android.os.Build;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070031import android.os.Handler;
32import android.os.IBinder;
Adrian Roos9ede1d22016-09-23 14:08:09 -070033import android.os.IRemoteCallback;
Galia Peycheva6861e912019-08-21 10:20:23 +020034import android.os.Looper;
Jeff Brown970d4132014-07-19 11:33:47 -070035import android.os.PowerManager;
36import android.os.RemoteException;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070037import android.os.ServiceManager;
Galia Peycheva6861e912019-08-21 10:20:23 +020038import android.util.Log;
Clara Bayarri75e09792015-07-29 16:20:40 +010039import android.util.MathUtils;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070040import android.util.Slog;
41import android.view.ActionMode;
Jeff Brown970d4132014-07-19 11:33:47 -070042import android.view.Display;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070043import android.view.KeyEvent;
44import android.view.Menu;
45import android.view.MenuItem;
46import android.view.MotionEvent;
Tim Kilbourn6a975b32015-04-09 17:14:34 -070047import android.view.SearchEvent;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070048import android.view.View;
49import android.view.ViewGroup;
50import android.view.Window;
51import android.view.WindowManager;
52import android.view.WindowManager.LayoutParams;
53import android.view.accessibility.AccessibilityEvent;
54
Jeff Brown26875502014-01-30 21:47:47 -080055import com.android.internal.util.DumpUtils;
56import com.android.internal.util.DumpUtils.Dump;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070057
Clara Bayarri75e09792015-07-29 16:20:40 +010058import java.io.FileDescriptor;
59import java.io.PrintWriter;
Clara Bayarri75e09792015-07-29 16:20:40 +010060
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070061/**
Scott Main6c9a1a12012-11-19 11:58:59 -080062 * Extend this class to implement a custom dream (available to the user as a "Daydream").
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070063 *
64 * <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a
65 * desk dock. Dreams provide another modality for apps to express themselves, tailored for
66 * an exhibition/lean-back experience.</p>
67 *
Scott Main6c9a1a12012-11-19 11:58:59 -080068 * <p>The {@code DreamService} lifecycle is as follows:</p>
Scott Main6237ac12012-10-08 22:30:29 -070069 * <ol>
70 * <li>{@link #onAttachedToWindow}
71 * <p>Use this for initial setup, such as calling {@link #setContentView setContentView()}.</li>
72 * <li>{@link #onDreamingStarted}
73 * <p>Your dream has started, so you should begin animations or other behaviors here.</li>
74 * <li>{@link #onDreamingStopped}
75 * <p>Use this to stop the things you started in {@link #onDreamingStarted}.</li>
76 * <li>{@link #onDetachedFromWindow}
Scott Main6c9a1a12012-11-19 11:58:59 -080077 * <p>Use this to dismantle resources (for example, detach from handlers
78 * and listeners).</li>
Scott Main6237ac12012-10-08 22:30:29 -070079 * </ol>
Daniel Sandler2d784902012-10-03 23:04:50 -040080 *
81 * <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
82 * initialization and teardown should be done by overriding the hooks above.</p>
83 *
Scott Main6c9a1a12012-11-19 11:58:59 -080084 * <p>To be available to the system, your {@code DreamService} should be declared in the
85 * manifest as follows:</p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070086 * <pre>
John Spurlock3a4d41a2012-10-01 09:30:49 -040087 * &lt;service
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070088 * android:name=".MyDream"
89 * android:exported="true"
90 * android:icon="@drawable/my_icon"
91 * android:label="@string/my_dream_label" >
92 *
John Spurlock3a4d41a2012-10-01 09:30:49 -040093 * &lt;intent-filter>
94 * &lt;action android:name="android.service.dreams.DreamService" />
95 * &lt;category android:name="android.intent.category.DEFAULT" />
96 * &lt;/intent-filter>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070097 *
John Spurlock3a4d41a2012-10-01 09:30:49 -040098 * &lt;!-- Point to additional information for this dream (optional) -->
99 * &lt;meta-data
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700100 * android:name="android.service.dream"
101 * android:resource="@xml/my_dream" />
John Spurlock3a4d41a2012-10-01 09:30:49 -0400102 * &lt;/service>
103 * </pre>
John Spurlock3a4d41a2012-10-01 09:30:49 -0400104 *
Neil Fuller71fbb812015-11-30 09:51:33 +0000105 * <p>If specified with the {@code <meta-data>} element,
Scott Main6237ac12012-10-08 22:30:29 -0700106 * additional information for the dream is defined using the
107 * {@link android.R.styleable#Dream &lt;dream&gt;} element in a separate XML file.
108 * Currently, the only addtional
109 * information you can provide is for a settings activity that allows the user to configure
110 * the dream behavior. For example:</p>
111 * <p class="code-caption">res/xml/my_dream.xml</p>
112 * <pre>
John Spurlock3a4d41a2012-10-01 09:30:49 -0400113 * &lt;dream xmlns:android="http://schemas.android.com/apk/res/android"
114 * android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700115 * </pre>
Scott Main6237ac12012-10-08 22:30:29 -0700116 * <p>This makes a Settings button available alongside your dream's listing in the
117 * system settings, which when pressed opens the specified activity.</p>
118 *
119 *
120 * <p>To specify your dream layout, call {@link #setContentView}, typically during the
121 * {@link #onAttachedToWindow} callback. For example:</p>
122 * <pre>
123 * public class MyDream extends DreamService {
124 *
125 * &#64;Override
126 * public void onAttachedToWindow() {
127 * super.onAttachedToWindow();
128 *
129 * // Exit dream upon user touch
130 * setInteractive(false);
131 * // Hide system UI
132 * setFullscreen(true);
133 * // Set the dream layout
134 * setContentView(R.layout.dream);
135 * }
136 * }
137 * </pre>
John Spurlockeb8d1be2014-06-25 17:46:15 -0400138 *
139 * <p>When targeting api level 21 and above, you must declare the service in your manifest file
140 * with the {@link android.Manifest.permission#BIND_DREAM_SERVICE} permission. For example:</p>
141 * <pre>
142 * &lt;service
143 * android:name=".MyDream"
144 * android:exported="true"
145 * android:icon="@drawable/my_icon"
146 * android:label="@string/my_dream_label"
Jeff Brown970d4132014-07-19 11:33:47 -0700147 * android:permission="android.permission.BIND_DREAM_SERVICE">
148 * &lt;intent-filter>
149 * &lt;action android:name=”android.service.dreams.DreamService” />
150 * &lt;category android:name=”android.intent.category.DEFAULT” />
151 * &lt;/intent-filter>
John Spurlockeb8d1be2014-06-25 17:46:15 -0400152 * &lt;/service>
153 * </pre>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700154 */
155public class DreamService extends Service implements Window.Callback {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700156 private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
157
158 /**
159 * The name of the dream manager service.
160 * @hide
161 */
162 public static final String DREAM_SERVICE = "dreams";
163
164 /**
165 * The {@link Intent} that must be declared as handled by the service.
166 */
167 @SdkConstant(SdkConstantType.SERVICE_ACTION)
168 public static final String SERVICE_INTERFACE =
169 "android.service.dreams.DreamService";
170
171 /**
172 * Name under which a Dream publishes information about itself.
173 * This meta-data must reference an XML resource containing
174 * a <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code>
175 * tag.
176 */
177 public static final String DREAM_META_DATA = "android.service.dream";
178
Galia Peycheva6861e912019-08-21 10:20:23 +0200179 private final IDreamManager mDreamManager;
180 private final Handler mHandler = new Handler(Looper.getMainLooper());
181 private IBinder mDreamToken;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700182 private Window mWindow;
Galia Peycheva6861e912019-08-21 10:20:23 +0200183 private Activity mActivity;
Jeff Brown344812d2014-04-02 20:00:36 -0700184 private boolean mInteractive;
Jeff Brown344812d2014-04-02 20:00:36 -0700185 private boolean mFullscreen;
Chris Wrena934fd12012-10-08 18:19:16 -0400186 private boolean mScreenBright = true;
Jeff Brown344812d2014-04-02 20:00:36 -0700187 private boolean mStarted;
Jeff Brownf6d46682014-07-17 22:44:20 -0700188 private boolean mWaking;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700189 private boolean mFinished;
Jeff Brown26875502014-01-30 21:47:47 -0800190 private boolean mCanDoze;
191 private boolean mDozing;
John Spurlockbf370992014-06-17 13:58:31 -0400192 private boolean mWindowless;
Jeff Brown970d4132014-07-19 11:33:47 -0700193 private int mDozeScreenState = Display.STATE_UNKNOWN;
194 private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700195
Daniel Sandler2d784902012-10-03 23:04:50 -0400196 private boolean mDebug = false;
197
Galia Peycheva6861e912019-08-21 10:20:23 +0200198 private DreamServiceWrapper mDreamServiceWrapper;
199 private Runnable mDispatchAfterOnAttachedToWindow;
200
Jeff Brown26875502014-01-30 21:47:47 -0800201 public DreamService() {
Galia Peycheva6861e912019-08-21 10:20:23 +0200202 mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
Jeff Brown26875502014-01-30 21:47:47 -0800203 }
204
Daniel Sandler2d784902012-10-03 23:04:50 -0400205 /**
206 * @hide
207 */
208 public void setDebug(boolean dbg) {
209 mDebug = dbg;
210 }
211
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700212 // begin Window.Callback methods
213 /** {@inheritDoc} */
214 @Override
215 public boolean dispatchKeyEvent(KeyEvent event) {
216 // TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK
217 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700218 if (mDebug) Slog.v(TAG, "Waking up on keyEvent");
219 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700220 return true;
221 } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700222 if (mDebug) Slog.v(TAG, "Waking up on back key");
223 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700224 return true;
225 }
226 return mWindow.superDispatchKeyEvent(event);
227 }
228
229 /** {@inheritDoc} */
230 @Override
231 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400232 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700233 if (mDebug) Slog.v(TAG, "Waking up on keyShortcutEvent");
234 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700235 return true;
236 }
237 return mWindow.superDispatchKeyShortcutEvent(event);
238 }
239
240 /** {@inheritDoc} */
241 @Override
242 public boolean dispatchTouchEvent(MotionEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400243 // TODO: create more flexible version of mInteractive that allows clicks
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700244 // but finish()es on any other kind of activity
Daniel Sandler2d784902012-10-03 23:04:50 -0400245 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700246 if (mDebug) Slog.v(TAG, "Waking up on touchEvent");
247 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700248 return true;
249 }
250 return mWindow.superDispatchTouchEvent(event);
251 }
252
253 /** {@inheritDoc} */
254 @Override
255 public boolean dispatchTrackballEvent(MotionEvent event) {
256 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700257 if (mDebug) Slog.v(TAG, "Waking up on trackballEvent");
258 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700259 return true;
260 }
261 return mWindow.superDispatchTrackballEvent(event);
262 }
263
264 /** {@inheritDoc} */
265 @Override
266 public boolean dispatchGenericMotionEvent(MotionEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400267 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700268 if (mDebug) Slog.v(TAG, "Waking up on genericMotionEvent");
269 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700270 return true;
271 }
272 return mWindow.superDispatchGenericMotionEvent(event);
273 }
274
275 /** {@inheritDoc} */
276 @Override
277 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
278 return false;
279 }
280
281 /** {@inheritDoc} */
282 @Override
283 public View onCreatePanelView(int featureId) {
284 return null;
285 }
286
287 /** {@inheritDoc} */
288 @Override
289 public boolean onCreatePanelMenu(int featureId, Menu menu) {
290 return false;
291 }
292
293 /** {@inheritDoc} */
294 @Override
295 public boolean onPreparePanel(int featureId, View view, Menu menu) {
296 return false;
297 }
298
299 /** {@inheritDoc} */
300 @Override
301 public boolean onMenuOpened(int featureId, Menu menu) {
302 return false;
303 }
304
305 /** {@inheritDoc} */
306 @Override
307 public boolean onMenuItemSelected(int featureId, MenuItem item) {
308 return false;
309 }
310
311 /** {@inheritDoc} */
312 @Override
313 public void onWindowAttributesChanged(LayoutParams attrs) {
314 }
315
316 /** {@inheritDoc} */
317 @Override
318 public void onContentChanged() {
319 }
320
321 /** {@inheritDoc} */
322 @Override
323 public void onWindowFocusChanged(boolean hasFocus) {
324 }
325
326 /** {@inheritDoc} */
327 @Override
328 public void onAttachedToWindow() {
329 }
330
331 /** {@inheritDoc} */
332 @Override
333 public void onDetachedFromWindow() {
334 }
335
336 /** {@inheritDoc} */
337 @Override
338 public void onPanelClosed(int featureId, Menu menu) {
339 }
340
341 /** {@inheritDoc} */
342 @Override
Tim Kilbourn6a975b32015-04-09 17:14:34 -0700343 public boolean onSearchRequested(SearchEvent event) {
344 return onSearchRequested();
345 }
346
347 /** {@inheritDoc} */
348 @Override
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700349 public boolean onSearchRequested() {
350 return false;
351 }
352
353 /** {@inheritDoc} */
354 @Override
355 public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) {
356 return null;
357 }
358
359 /** {@inheritDoc} */
360 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +0000361 public ActionMode onWindowStartingActionMode(
362 android.view.ActionMode.Callback callback, int type) {
363 return null;
364 }
365
366 /** {@inheritDoc} */
367 @Override
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700368 public void onActionModeStarted(ActionMode mode) {
369 }
370
371 /** {@inheritDoc} */
372 @Override
373 public void onActionModeFinished(ActionMode mode) {
374 }
375 // end Window.Callback methods
376
377 // begin public api
378 /**
379 * Retrieves the current {@link android.view.WindowManager} for the dream.
380 * Behaves similarly to {@link android.app.Activity#getWindowManager()}.
381 *
382 * @return The current window manager, or null if the dream is not started.
383 */
384 public WindowManager getWindowManager() {
Jeff Brown344812d2014-04-02 20:00:36 -0700385 return mWindow != null ? mWindow.getWindowManager() : null;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700386 }
387
388 /**
389 * Retrieves the current {@link android.view.Window} for the dream.
390 * Behaves similarly to {@link android.app.Activity#getWindow()}.
391 *
392 * @return The current window, or null if the dream is not started.
393 */
394 public Window getWindow() {
395 return mWindow;
396 }
397
398 /**
399 * Inflates a layout resource and set it to be the content view for this Dream.
400 * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
401 *
402 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
403 *
404 * @param layoutResID Resource ID to be inflated.
Daniel Sandler2d784902012-10-03 23:04:50 -0400405 *
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700406 * @see #setContentView(android.view.View)
407 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
408 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700409 public void setContentView(@LayoutRes int layoutResID) {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700410 getWindow().setContentView(layoutResID);
411 }
412
413 /**
414 * Sets a view to be the content view for this Dream.
Scott Main6237ac12012-10-08 22:30:29 -0700415 * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity,
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700416 * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
417 *
Scott Main6237ac12012-10-08 22:30:29 -0700418 * <p>Note: This requires a window, so you should usually call it during
419 * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
420 * during {@link #onCreate}).</p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700421 *
422 * @see #setContentView(int)
423 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
424 */
425 public void setContentView(View view) {
426 getWindow().setContentView(view);
427 }
428
429 /**
430 * Sets a view to be the content view for this Dream.
Daniel Sandler2d784902012-10-03 23:04:50 -0400431 * Behaves similarly to
Scott Main6237ac12012-10-08 22:30:29 -0700432 * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
433 * in an activity.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700434 *
Scott Main6237ac12012-10-08 22:30:29 -0700435 * <p>Note: This requires a window, so you should usually call it during
436 * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
437 * during {@link #onCreate}).</p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700438 *
439 * @param view The desired content to display.
440 * @param params Layout parameters for the view.
441 *
442 * @see #setContentView(android.view.View)
443 * @see #setContentView(int)
444 */
445 public void setContentView(View view, ViewGroup.LayoutParams params) {
446 getWindow().setContentView(view, params);
447 }
448
449 /**
450 * Adds a view to the Dream's window, leaving other content views in place.
451 *
452 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
453 *
454 * @param view The desired content to display.
455 * @param params Layout parameters for the view.
456 */
457 public void addContentView(View view, ViewGroup.LayoutParams params) {
458 getWindow().addContentView(view, params);
459 }
460
461 /**
462 * Finds a view that was identified by the id attribute from the XML that
463 * was processed in {@link #onCreate}.
464 *
465 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
Chris Craik6faa9e52018-01-11 10:46:10 -0800466 * <p>
467 * <strong>Note:</strong> In most cases -- depending on compiler support --
468 * the resulting view is automatically cast to the target class type. If
469 * the target class type is unconstrained, an explicit cast may be
470 * necessary.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700471 *
Chris Craik6faa9e52018-01-11 10:46:10 -0800472 * @param id the ID to search for
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700473 * @return The view if found or null otherwise.
Chris Craik6faa9e52018-01-11 10:46:10 -0800474 * @see View#findViewById(int)
475 * @see DreamService#requireViewById(int)
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700476 */
Scott Kennedyc0519552015-02-11 15:33:10 -0800477 @Nullable
Alan Viverette04fd4702017-04-13 16:37:06 -0400478 public <T extends View> T findViewById(@IdRes int id) {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700479 return getWindow().findViewById(id);
480 }
481
482 /**
Chris Craik6faa9e52018-01-11 10:46:10 -0800483 * Finds a view that was identified by the id attribute from the XML that was processed in
484 * {@link #onCreate}, or throws an IllegalArgumentException if the ID is invalid or there is no
485 * matching view in the hierarchy.
486 *
487 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
488 * <p>
489 * <strong>Note:</strong> In most cases -- depending on compiler support --
490 * the resulting view is automatically cast to the target class type. If
491 * the target class type is unconstrained, an explicit cast may be
492 * necessary.
493 *
494 * @param id the ID to search for
495 * @return a view with given ID
496 * @see View#requireViewById(int)
497 * @see DreamService#findViewById(int)
498 */
499 @NonNull
500 public final <T extends View> T requireViewById(@IdRes int id) {
501 T view = findViewById(id);
502 if (view == null) {
503 throw new IllegalArgumentException(
504 "ID does not reference a View inside this DreamService");
505 }
506 return view;
507 }
508
509 /**
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700510 * Marks this dream as interactive to receive input events.
511 *
512 * <p>Non-interactive dreams (default) will dismiss on the first input event.</p>
513 *
514 * <p>Interactive dreams should call {@link #finish()} to dismiss themselves.</p>
515 *
516 * @param interactive True if this dream will handle input events.
517 */
518 public void setInteractive(boolean interactive) {
519 mInteractive = interactive;
520 }
521
522 /**
523 * Returns whether or not this dream is interactive. Defaults to false.
524 *
525 * @see #setInteractive(boolean)
526 */
527 public boolean isInteractive() {
528 return mInteractive;
529 }
530
531 /**
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700532 * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
533 * on the dream's window.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700534 *
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700535 * @param fullscreen If true, the fullscreen flag will be set; else it
536 * will be cleared.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700537 */
538 public void setFullscreen(boolean fullscreen) {
Jeff Brown26875502014-01-30 21:47:47 -0800539 if (mFullscreen != fullscreen) {
540 mFullscreen = fullscreen;
541 int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
542 applyWindowFlags(mFullscreen ? flag : 0, flag);
543 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700544 }
545
546 /**
547 * Returns whether or not this dream is in fullscreen mode. Defaults to false.
548 *
549 * @see #setFullscreen(boolean)
550 */
551 public boolean isFullscreen() {
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700552 return mFullscreen;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700553 }
554
555 /**
556 * Marks this dream as keeping the screen bright while dreaming.
557 *
558 * @param screenBright True to keep the screen bright while dreaming.
559 */
560 public void setScreenBright(boolean screenBright) {
Jeff Brown26875502014-01-30 21:47:47 -0800561 if (mScreenBright != screenBright) {
562 mScreenBright = screenBright;
563 int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
564 applyWindowFlags(mScreenBright ? flag : 0, flag);
565 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700566 }
567
568 /**
Jeff Brown26875502014-01-30 21:47:47 -0800569 * Returns whether or not this dream keeps the screen bright while dreaming.
570 * Defaults to false, allowing the screen to dim if necessary.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700571 *
572 * @see #setScreenBright(boolean)
573 */
574 public boolean isScreenBright() {
575 return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright);
576 }
577
578 /**
John Spurlockbf370992014-06-17 13:58:31 -0400579 * Marks this dream as windowless. Only available to doze dreams.
580 *
581 * @hide
Galia Peycheva52e89222020-02-18 23:41:43 +0100582 *
John Spurlockbf370992014-06-17 13:58:31 -0400583 */
584 public void setWindowless(boolean windowless) {
585 mWindowless = windowless;
586 }
587
588 /**
589 * Returns whether or not this dream is windowless. Only available to doze dreams.
590 *
591 * @hide
592 */
593 public boolean isWindowless() {
594 return mWindowless;
595 }
596
597 /**
Jeff Brown26875502014-01-30 21:47:47 -0800598 * Returns true if this dream is allowed to doze.
599 * <p>
600 * The value returned by this method is only meaningful when the dream has started.
601 * </p>
602 *
603 * @return True if this dream can doze.
604 * @see #startDozing
Jeff Brown970d4132014-07-19 11:33:47 -0700605 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800606 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100607 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown26875502014-01-30 21:47:47 -0800608 public boolean canDoze() {
609 return mCanDoze;
610 }
611
612 /**
613 * Starts dozing, entering a deep dreamy sleep.
614 * <p>
615 * Dozing enables the system to conserve power while the user is not actively interacting
616 * with the device. While dozing, the display will remain on in a low-power state
617 * and will continue to show its previous contents but the application processor and
618 * other system components will be allowed to suspend when possible.
619 * </p><p>
620 * While the application processor is suspended, the dream may stop executing code
621 * for long periods of time. Prior to being suspended, the dream may schedule periodic
622 * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
623 * The dream may also keep the CPU awake by acquiring a
624 * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
625 * Note that since the purpose of doze mode is to conserve power (especially when
626 * running on battery), the dream should not wake the CPU very often or keep it
627 * awake for very long.
628 * </p><p>
629 * It is a good idea to call this method some time after the dream's entry animation
630 * has completed and the dream is ready to doze. It is important to completely
631 * finish all of the work needed before dozing since the application processor may
632 * be suspended at any moment once this method is called unless other wake locks
633 * are being held.
634 * </p><p>
635 * Call {@link #stopDozing} or {@link #finish} to stop dozing.
636 * </p>
637 *
638 * @see #stopDozing
Jeff Brown970d4132014-07-19 11:33:47 -0700639 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800640 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100641 @UnsupportedAppUsage
Jeff Brown26875502014-01-30 21:47:47 -0800642 public void startDozing() {
643 if (mCanDoze && !mDozing) {
644 mDozing = true;
Jeff Brown970d4132014-07-19 11:33:47 -0700645 updateDoze();
646 }
647 }
648
649 private void updateDoze() {
Galia Peycheva6861e912019-08-21 10:20:23 +0200650 if (mDreamToken == null) {
651 Slog.w(TAG, "Updating doze without a dream token.");
Erik Wolsheimer5fb10702017-11-15 12:08:32 -0800652 return;
653 }
654
Jeff Brown970d4132014-07-19 11:33:47 -0700655 if (mDozing) {
Jeff Brown26875502014-01-30 21:47:47 -0800656 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200657 mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
Jeff Brown26875502014-01-30 21:47:47 -0800658 } catch (RemoteException ex) {
659 // system server died
660 }
661 }
662 }
663
664 /**
665 * Stops dozing, returns to active dreaming.
666 * <p>
667 * This method reverses the effect of {@link #startDozing}. From this moment onward,
668 * the application processor will be kept awake as long as the dream is running
669 * or until the dream starts dozing again.
670 * </p>
671 *
672 * @see #startDozing
Jeff Brown970d4132014-07-19 11:33:47 -0700673 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800674 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100675 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown26875502014-01-30 21:47:47 -0800676 public void stopDozing() {
677 if (mDozing) {
678 mDozing = false;
679 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200680 mDreamManager.stopDozing(mDreamToken);
Jeff Brown26875502014-01-30 21:47:47 -0800681 } catch (RemoteException ex) {
682 // system server died
683 }
684 }
685 }
686
687 /**
688 * Returns true if the dream will allow the system to enter a low-power state while
689 * it is running without actually turning off the screen. Defaults to false,
690 * keeping the application processor awake while the dream is running.
691 *
692 * @return True if the dream is dozing.
693 *
694 * @see #setDozing(boolean)
Jeff Brown970d4132014-07-19 11:33:47 -0700695 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800696 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100697 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown26875502014-01-30 21:47:47 -0800698 public boolean isDozing() {
699 return mDozing;
700 }
701
702 /**
Jeff Brown970d4132014-07-19 11:33:47 -0700703 * Gets the screen state to use while dozing.
704 *
705 * @return The screen state to use while dozing, such as {@link Display#STATE_ON},
706 * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
Chris Phoenix10a4a642017-09-25 13:21:00 -0700707 * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
708 * for the default behavior.
Jeff Brown970d4132014-07-19 11:33:47 -0700709 *
710 * @see #setDozeScreenState
711 * @hide For use by system UI components only.
712 */
713 public int getDozeScreenState() {
714 return mDozeScreenState;
715 }
716
717 /**
718 * Sets the screen state to use while dozing.
719 * <p>
720 * The value of this property determines the power state of the primary display
721 * once {@link #startDozing} has been called. The default value is
722 * {@link Display#STATE_UNKNOWN} which lets the system decide.
723 * The dream may set a different state before starting to doze and may
724 * perform transitions between states while dozing to conserve power and
725 * achieve various effects.
726 * </p><p>
Chris Phoenix10a4a642017-09-25 13:21:00 -0700727 * Some devices will have dedicated hardware ("Sidekick") to animate
728 * the display content while the CPU sleeps. If the dream and the hardware support
729 * this, {@link Display#STATE_ON_SUSPEND} or {@link Display#STATE_DOZE_SUSPEND}
730 * will switch control to the Sidekick.
731 * </p><p>
732 * If not using Sidekick, it is recommended that the state be set to
733 * {@link Display#STATE_DOZE_SUSPEND} once the dream has completely
734 * finished drawing and before it releases its wakelock
735 * to allow the display hardware to be fully suspended. While suspended,
736 * the display will preserve its on-screen contents.
737 * </p><p>
738 * If the doze suspend state is used, the dream must make sure to set the mode back
Jeff Brown970d4132014-07-19 11:33:47 -0700739 * to {@link Display#STATE_DOZE} or {@link Display#STATE_ON} before drawing again
740 * since the display updates may be ignored and not seen by the user otherwise.
741 * </p><p>
742 * The set of available display power states and their behavior while dozing is
743 * hardware dependent and may vary across devices. The dream may therefore
744 * need to be modified or configured to correctly support the hardware.
745 * </p>
746 *
747 * @param state The screen state to use while dozing, such as {@link Display#STATE_ON},
748 * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
Chris Phoenix10a4a642017-09-25 13:21:00 -0700749 * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
750 * for the default behavior.
Jeff Brown970d4132014-07-19 11:33:47 -0700751 *
752 * @hide For use by system UI components only.
753 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100754 @UnsupportedAppUsage
Jeff Brown970d4132014-07-19 11:33:47 -0700755 public void setDozeScreenState(int state) {
756 if (mDozeScreenState != state) {
757 mDozeScreenState = state;
758 updateDoze();
759 }
760 }
761
762 /**
763 * Gets the screen brightness to use while dozing.
764 *
765 * @return The screen brightness while dozing as a value between
766 * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
767 * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
768 * its default policy based on the screen state.
769 *
770 * @see #setDozeScreenBrightness
771 * @hide For use by system UI components only.
772 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100773 @UnsupportedAppUsage
Jeff Brown970d4132014-07-19 11:33:47 -0700774 public int getDozeScreenBrightness() {
775 return mDozeScreenBrightness;
776 }
777
778 /**
779 * Sets the screen brightness to use while dozing.
780 * <p>
781 * The value of this property determines the power state of the primary display
782 * once {@link #startDozing} has been called. The default value is
783 * {@link PowerManager#BRIGHTNESS_DEFAULT} which lets the system decide.
784 * The dream may set a different brightness before starting to doze and may adjust
785 * the brightness while dozing to conserve power and achieve various effects.
786 * </p><p>
787 * Note that dream may specify any brightness in the full 0-255 range, including
788 * values that are less than the minimum value for manual screen brightness
789 * adjustments by the user. In particular, the value may be set to 0 which may
790 * turn off the backlight entirely while still leaving the screen on although
791 * this behavior is device dependent and not guaranteed.
792 * </p><p>
793 * The available range of display brightness values and their behavior while dozing is
794 * hardware dependent and may vary across devices. The dream may therefore
795 * need to be modified or configured to correctly support the hardware.
796 * </p>
797 *
798 * @param brightness The screen brightness while dozing as a value between
799 * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
800 * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
801 * its default policy based on the screen state.
802 *
803 * @hide For use by system UI components only.
804 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100805 @UnsupportedAppUsage
Jeff Brown970d4132014-07-19 11:33:47 -0700806 public void setDozeScreenBrightness(int brightness) {
807 if (brightness != PowerManager.BRIGHTNESS_DEFAULT) {
808 brightness = clampAbsoluteBrightness(brightness);
809 }
810 if (mDozeScreenBrightness != brightness) {
811 mDozeScreenBrightness = brightness;
812 updateDoze();
813 }
814 }
815
816 /**
Daniel Sandler2d784902012-10-03 23:04:50 -0400817 * Called when this Dream is constructed.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700818 */
819 @Override
820 public void onCreate() {
Jeff Brown970d4132014-07-19 11:33:47 -0700821 if (mDebug) Slog.v(TAG, "onCreate()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700822 super.onCreate();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700823 }
824
825 /**
Daniel Sandler2d784902012-10-03 23:04:50 -0400826 * Called when the dream's window has been created and is visible and animation may now begin.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700827 */
Daniel Sandler2d784902012-10-03 23:04:50 -0400828 public void onDreamingStarted() {
829 if (mDebug) Slog.v(TAG, "onDreamingStarted()");
830 // hook for subclasses
831 }
832
833 /**
834 * Called when this Dream is stopped, either by external request or by calling finish(),
835 * before the window has been removed.
836 */
837 public void onDreamingStopped() {
838 if (mDebug) Slog.v(TAG, "onDreamingStopped()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700839 // hook for subclasses
840 }
841
Jeff Brownf6d46682014-07-17 22:44:20 -0700842 /**
843 * Called when the dream is being asked to stop itself and wake.
844 * <p>
845 * The default implementation simply calls {@link #finish} which ends the dream
846 * immediately. Subclasses may override this function to perform a smooth exit
847 * transition then call {@link #finish} afterwards.
848 * </p><p>
849 * Note that the dream will only be given a short period of time (currently about
850 * five seconds) to wake up. If the dream does not finish itself in a timely manner
851 * then the system will forcibly finish it once the time allowance is up.
852 * </p>
853 */
854 public void onWakeUp() {
Jerry Chang30efde62020-02-24 18:03:33 +0800855 finish();
Jeff Brownf6d46682014-07-17 22:44:20 -0700856 }
857
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700858 /** {@inheritDoc} */
859 @Override
860 public final IBinder onBind(Intent intent) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400861 if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
Galia Peycheva6861e912019-08-21 10:20:23 +0200862 mDreamServiceWrapper = new DreamServiceWrapper();
863 return mDreamServiceWrapper;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700864 }
865
866 /**
Jeff Brown26875502014-01-30 21:47:47 -0800867 * Stops the dream and detaches from the window.
868 * <p>
869 * When the dream ends, the system will be allowed to go to sleep fully unless there
870 * is a reason for it to be awake such as recent user activity or wake locks being held.
871 * </p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700872 */
Daniel Sandler2d784902012-10-03 23:04:50 -0400873 public final void finish() {
Jeff Brownf6d46682014-07-17 22:44:20 -0700874 if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished);
875
Galia Peycheva95b12342020-04-02 19:56:05 +0200876 Activity activity = mActivity;
877 if (activity != null) {
878 if (!activity.isFinishing()) {
Jerry Chang30efde62020-02-24 18:03:33 +0800879 // In case the activity is not finished yet, do it now.
Galia Peycheva95b12342020-04-02 19:56:05 +0200880 activity.finishAndRemoveTask();
Jerry Chang30efde62020-02-24 18:03:33 +0800881 }
Jerry Changb050ab82020-03-10 10:21:27 +0800882 return;
Galia Peycheva6861e912019-08-21 10:20:23 +0200883 }
884
Jerry Changb050ab82020-03-10 10:21:27 +0800885 if (mFinished) {
886 return;
887 }
888 mFinished = true;
Jeff Brownf6d46682014-07-17 22:44:20 -0700889
Jerry Changb050ab82020-03-10 10:21:27 +0800890 if (mDreamToken == null) {
891 Slog.w(TAG, "Finish was called before the dream was attached.");
892 stopSelf();
893 return;
894 }
895
896 try {
897 // finishSelf will unbind the dream controller from the dream service. This will
898 // trigger DreamService.this.onDestroy and DreamService.this will die.
899 mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
900 } catch (RemoteException ex) {
901 // system server died
Jeff Brownf6d46682014-07-17 22:44:20 -0700902 }
903 }
904
905 /**
906 * Wakes the dream up gently.
907 * <p>
908 * Calls {@link #onWakeUp} to give the dream a chance to perform an exit transition.
909 * When the transition is over, the dream should call {@link #finish}.
910 * </p>
911 */
912 public final void wakeUp() {
913 wakeUp(false);
914 }
915
916 private void wakeUp(boolean fromSystem) {
917 if (mDebug) Slog.v(TAG, "wakeUp(): fromSystem=" + fromSystem
918 + ", mWaking=" + mWaking + ", mFinished=" + mFinished);
919
920 if (!mWaking && !mFinished) {
921 mWaking = true;
922
923 // As a minor optimization, invoke the callback first in case it simply
924 // calls finish() immediately so there wouldn't be much point in telling
925 // the system that we are finishing the dream gently.
926 onWakeUp();
927
928 // Now tell the system we are waking gently, unless we already told
929 // it we were finishing immediately.
930 if (!fromSystem && !mFinished) {
Galia Peycheva6861e912019-08-21 10:20:23 +0200931 if (mActivity == null) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700932 Slog.w(TAG, "WakeUp was called before the dream was attached.");
933 } else {
934 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200935 mDreamManager.finishSelf(mDreamToken, false /*immediate*/);
Jeff Brownf6d46682014-07-17 22:44:20 -0700936 } catch (RemoteException ex) {
937 // system server died
938 }
939 }
940 }
941 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700942 }
943
944 /** {@inheritDoc} */
945 @Override
946 public void onDestroy() {
Daniel Sandler2d784902012-10-03 23:04:50 -0400947 if (mDebug) Slog.v(TAG, "onDestroy()");
Daniel Sandler2d784902012-10-03 23:04:50 -0400948 // hook for subclasses
Daniel Sandlerc1310702012-10-09 17:44:45 -0700949
950 // Just in case destroy came in before detach, let's take care of that now
951 detach();
952
953 super.onDestroy();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700954 }
Daniel Sandler2d784902012-10-03 23:04:50 -0400955
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700956 // end public api
957
Daniel Sandler2d784902012-10-03 23:04:50 -0400958 /**
Daniel Sandlerc1310702012-10-09 17:44:45 -0700959 * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
Daniel Sandler2d784902012-10-03 23:04:50 -0400960 *
961 * Must run on mHandler.
962 */
963 private final void detach() {
Jeff Brown344812d2014-04-02 20:00:36 -0700964 if (mStarted) {
965 if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
966 mStarted = false;
967 onDreamingStopped();
Daniel Sandler2d784902012-10-03 23:04:50 -0400968 }
969
Galia Peycheva6861e912019-08-21 10:20:23 +0200970 if (mActivity != null && !mActivity.isFinishing()) {
971 mActivity.finishAndRemoveTask();
Galia Peycheva52e89222020-02-18 23:41:43 +0100972 } else {
973 finish();
Jeff Brown344812d2014-04-02 20:00:36 -0700974 }
Daniel Sandler2d784902012-10-03 23:04:50 -0400975
Galia Peycheva6861e912019-08-21 10:20:23 +0200976 mDreamToken = null;
977 mCanDoze = false;
Daniel Sandler2d784902012-10-03 23:04:50 -0400978 }
979
980 /**
981 * Called when the Dream is ready to be shown.
982 *
983 * Must run on mHandler.
984 *
Galia Peycheva6861e912019-08-21 10:20:23 +0200985 * @param dreamToken Token for this dream service.
Adrian Roos9ede1d22016-09-23 14:08:09 -0700986 * @param started A callback that will be invoked once onDreamingStarted has completed.
Daniel Sandler2d784902012-10-03 23:04:50 -0400987 */
Galia Peycheva6861e912019-08-21 10:20:23 +0200988 private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
Jerry Chang30efde62020-02-24 18:03:33 +0800989 if (mDreamToken != null) {
Galia Peycheva6861e912019-08-21 10:20:23 +0200990 Slog.e(TAG, "attach() called when dream with token=" + mDreamToken
991 + " already attached");
Adrian Roos9ede1d22016-09-23 14:08:09 -0700992 return;
Adrian Roos7445c0b2016-09-06 16:45:46 -0700993 }
Adrian Roos9ede1d22016-09-23 14:08:09 -0700994 if (mFinished || mWaking) {
995 Slog.w(TAG, "attach() called after dream already finished");
996 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200997 mDreamManager.finishSelf(dreamToken, true /*immediate*/);
Adrian Roos9ede1d22016-09-23 14:08:09 -0700998 } catch (RemoteException ex) {
999 // system server died
1000 }
1001 return;
1002 }
1003
Galia Peycheva6861e912019-08-21 10:20:23 +02001004 mDreamToken = dreamToken;
Adrian Roos9ede1d22016-09-23 14:08:09 -07001005 mCanDoze = canDoze;
1006 if (mWindowless && !mCanDoze) {
1007 throw new IllegalStateException("Only doze dreams can be windowless");
1008 }
Adrian Roos9ede1d22016-09-23 14:08:09 -07001009
Galia Peycheva6861e912019-08-21 10:20:23 +02001010 mDispatchAfterOnAttachedToWindow = () -> {
1011 if (mWindow != null || mWindowless) {
1012 mStarted = true;
1013 try {
1014 onDreamingStarted();
1015 } finally {
Adrian Roos9ede1d22016-09-23 14:08:09 -07001016 try {
Galia Peycheva6861e912019-08-21 10:20:23 +02001017 started.sendResult(null);
1018 } catch (RemoteException e) {
1019 throw e.rethrowFromSystemServer();
Adrian Roos9ede1d22016-09-23 14:08:09 -07001020 }
1021 }
1022 }
Galia Peycheva6861e912019-08-21 10:20:23 +02001023 };
1024
1025 // We need to defer calling onDreamingStarted until after the activity is created.
1026 // If the dream is windowless, we can call it immediately. Otherwise, we wait
1027 // for the DreamActivity to report onActivityCreated via
1028 // DreamServiceWrapper.onActivityCreated.
1029 if (!mWindowless) {
1030 Intent i = new Intent(this, DreamActivity.class);
Galia Peychevaed401cc2020-03-19 20:28:09 +01001031 i.setPackage(getApplicationContext().getPackageName());
Galia Peycheva6861e912019-08-21 10:20:23 +02001032 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1033 i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
1034
1035 try {
1036 if (!ActivityTaskManager.getService().startDreamActivity(i)) {
1037 detach();
1038 return;
1039 }
1040 } catch (RemoteException e) {
1041 Log.w(TAG, "Could not connect to activity task manager to start dream activity");
1042 e.rethrowFromSystemServer();
1043 }
1044 } else {
1045 mDispatchAfterOnAttachedToWindow.run();
1046 }
1047 }
1048
1049 private void onWindowCreated(Window w) {
1050 mWindow = w;
1051 mWindow.setCallback(this);
Galia Peycheva6861e912019-08-21 10:20:23 +02001052 mWindow.requestFeature(Window.FEATURE_NO_TITLE);
1053
1054 WindowManager.LayoutParams lp = mWindow.getAttributes();
1055 lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
1056 lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
1057 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
1058 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
1059 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
1060 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
1061 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
1062 | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
1063 | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
1064 );
1065 mWindow.setAttributes(lp);
1066 // Workaround: Currently low-profile and in-window system bar backgrounds don't go
1067 // along well. Dreams usually don't need such bars anyways, so disable them by default.
1068 mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
1069
Galia Peycheva6861e912019-08-21 10:20:23 +02001070 mWindow.getDecorView().addOnAttachStateChangeListener(
1071 new View.OnAttachStateChangeListener() {
1072 @Override
1073 public void onViewAttachedToWindow(View v) {
1074 mDispatchAfterOnAttachedToWindow.run();
1075 }
1076
1077 @Override
1078 public void onViewDetachedFromWindow(View v) {
Galia Peycheva95b12342020-04-02 19:56:05 +02001079 mActivity = null;
Galia Peycheva6861e912019-08-21 10:20:23 +02001080 finish();
1081 }
1082 });
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001083 }
1084
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001085 private boolean getWindowFlagValue(int flag, boolean defaultValue) {
1086 return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0;
1087 }
1088
1089 private void applyWindowFlags(int flags, int mask) {
1090 if (mWindow != null) {
1091 WindowManager.LayoutParams lp = mWindow.getAttributes();
1092 lp.flags = applyFlags(lp.flags, flags, mask);
1093 mWindow.setAttributes(lp);
Jeff Brown344812d2014-04-02 20:00:36 -07001094 mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001095 }
1096 }
1097
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001098 private int applyFlags(int oldFlags, int flags, int mask) {
1099 return (oldFlags&~mask) | (flags&mask);
1100 }
1101
Daniel Sandler2d784902012-10-03 23:04:50 -04001102 @Override
John Spurlock66127272014-06-28 11:27:17 -04001103 protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) {
Jeff Brown26875502014-01-30 21:47:47 -08001104 DumpUtils.dumpAsync(mHandler, new Dump() {
1105 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001106 public void dump(PrintWriter pw, String prefix) {
John Spurlock66127272014-06-28 11:27:17 -04001107 dumpOnHandler(fd, pw, args);
Jeff Brown26875502014-01-30 21:47:47 -08001108 }
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001109 }, pw, "", 1000);
Daniel Sandler2d784902012-10-03 23:04:50 -04001110 }
1111
John Spurlock66127272014-06-28 11:27:17 -04001112 /** @hide */
1113 protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
1114 pw.print(TAG + ": ");
Galia Peycheva6861e912019-08-21 10:20:23 +02001115 if (mFinished) {
John Spurlock66127272014-06-28 11:27:17 -04001116 pw.println("stopped");
1117 } else {
Galia Peycheva6861e912019-08-21 10:20:23 +02001118 pw.println("running (dreamToken=" + mDreamToken + ")");
John Spurlock66127272014-06-28 11:27:17 -04001119 }
1120 pw.println(" window: " + mWindow);
1121 pw.print(" flags:");
1122 if (isInteractive()) pw.print(" interactive");
John Spurlock66127272014-06-28 11:27:17 -04001123 if (isFullscreen()) pw.print(" fullscreen");
1124 if (isScreenBright()) pw.print(" bright");
1125 if (isWindowless()) pw.print(" windowless");
1126 if (isDozing()) pw.print(" dozing");
Jeff Brown970d4132014-07-19 11:33:47 -07001127 else if (canDoze()) pw.print(" candoze");
John Spurlock66127272014-06-28 11:27:17 -04001128 pw.println();
Jeff Brown970d4132014-07-19 11:33:47 -07001129 if (canDoze()) {
Jeff Brown970d4132014-07-19 11:33:47 -07001130 pw.println(" doze screen state: " + Display.stateToString(mDozeScreenState));
1131 pw.println(" doze screen brightness: " + mDozeScreenBrightness);
1132 }
1133 }
1134
1135 private static int clampAbsoluteBrightness(int value) {
1136 return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
John Spurlock66127272014-06-28 11:27:17 -04001137 }
1138
Galia Peycheva6861e912019-08-21 10:20:23 +02001139 /**
1140 * The DreamServiceWrapper is used as a gateway to the system_server, where DreamController
1141 * uses it to control the DreamService. It is also used to receive callbacks from the
1142 * DreamActivity.
1143 */
1144 final class DreamServiceWrapper extends IDreamService.Stub {
Jeff Brown26875502014-01-30 21:47:47 -08001145 @Override
Galia Peycheva6861e912019-08-21 10:20:23 +02001146 public void attach(final IBinder dreamToken, final boolean canDoze,
Adrian Roos9ede1d22016-09-23 14:08:09 -07001147 IRemoteCallback started) {
Galia Peycheva6861e912019-08-21 10:20:23 +02001148 mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started));
Daniel Sandler2d784902012-10-03 23:04:50 -04001149 }
Jeff Brown26875502014-01-30 21:47:47 -08001150
1151 @Override
Daniel Sandler2d784902012-10-03 23:04:50 -04001152 public void detach() {
Galia Peychevaa8e464122020-02-14 19:00:29 +01001153 mHandler.post(DreamService.this::detach);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001154 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001155
Jeff Brownf6d46682014-07-17 22:44:20 -07001156 @Override
1157 public void wakeUp() {
Galia Peychevaa8e464122020-02-14 19:00:29 +01001158 mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
Jeff Brownf6d46682014-07-17 22:44:20 -07001159 }
Galia Peycheva6861e912019-08-21 10:20:23 +02001160
1161 /** @hide */
1162 void onActivityCreated(DreamActivity a) {
1163 mActivity = a;
1164 onWindowCreated(a.getWindow());
1165 }
Jeff Brownf6d46682014-07-17 22:44:20 -07001166 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001167}