blob: 3f0787350075db51fba811c0b9bd784e78c1a54b [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;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700185 private boolean mLowProfile = true;
Jeff Brown344812d2014-04-02 20:00:36 -0700186 private boolean mFullscreen;
Chris Wrena934fd12012-10-08 18:19:16 -0400187 private boolean mScreenBright = true;
Jeff Brown344812d2014-04-02 20:00:36 -0700188 private boolean mStarted;
Jeff Brownf6d46682014-07-17 22:44:20 -0700189 private boolean mWaking;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700190 private boolean mFinished;
Jeff Brown26875502014-01-30 21:47:47 -0800191 private boolean mCanDoze;
192 private boolean mDozing;
John Spurlockbf370992014-06-17 13:58:31 -0400193 private boolean mWindowless;
Jeff Brown970d4132014-07-19 11:33:47 -0700194 private int mDozeScreenState = Display.STATE_UNKNOWN;
195 private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700196
Daniel Sandler2d784902012-10-03 23:04:50 -0400197 private boolean mDebug = false;
198
Galia Peycheva6861e912019-08-21 10:20:23 +0200199 private DreamServiceWrapper mDreamServiceWrapper;
200 private Runnable mDispatchAfterOnAttachedToWindow;
201
Jeff Brown26875502014-01-30 21:47:47 -0800202 public DreamService() {
Galia Peycheva6861e912019-08-21 10:20:23 +0200203 mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
Jeff Brown26875502014-01-30 21:47:47 -0800204 }
205
Daniel Sandler2d784902012-10-03 23:04:50 -0400206 /**
207 * @hide
208 */
209 public void setDebug(boolean dbg) {
210 mDebug = dbg;
211 }
212
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700213 // begin Window.Callback methods
214 /** {@inheritDoc} */
215 @Override
216 public boolean dispatchKeyEvent(KeyEvent event) {
217 // TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK
218 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700219 if (mDebug) Slog.v(TAG, "Waking up on keyEvent");
220 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700221 return true;
222 } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700223 if (mDebug) Slog.v(TAG, "Waking up on back key");
224 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700225 return true;
226 }
227 return mWindow.superDispatchKeyEvent(event);
228 }
229
230 /** {@inheritDoc} */
231 @Override
232 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400233 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700234 if (mDebug) Slog.v(TAG, "Waking up on keyShortcutEvent");
235 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700236 return true;
237 }
238 return mWindow.superDispatchKeyShortcutEvent(event);
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public boolean dispatchTouchEvent(MotionEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400244 // TODO: create more flexible version of mInteractive that allows clicks
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700245 // but finish()es on any other kind of activity
Daniel Sandler2d784902012-10-03 23:04:50 -0400246 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700247 if (mDebug) Slog.v(TAG, "Waking up on touchEvent");
248 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700249 return true;
250 }
251 return mWindow.superDispatchTouchEvent(event);
252 }
253
254 /** {@inheritDoc} */
255 @Override
256 public boolean dispatchTrackballEvent(MotionEvent event) {
257 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700258 if (mDebug) Slog.v(TAG, "Waking up on trackballEvent");
259 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700260 return true;
261 }
262 return mWindow.superDispatchTrackballEvent(event);
263 }
264
265 /** {@inheritDoc} */
266 @Override
267 public boolean dispatchGenericMotionEvent(MotionEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400268 if (!mInteractive) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700269 if (mDebug) Slog.v(TAG, "Waking up on genericMotionEvent");
270 wakeUp();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700271 return true;
272 }
273 return mWindow.superDispatchGenericMotionEvent(event);
274 }
275
276 /** {@inheritDoc} */
277 @Override
278 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
279 return false;
280 }
281
282 /** {@inheritDoc} */
283 @Override
284 public View onCreatePanelView(int featureId) {
285 return null;
286 }
287
288 /** {@inheritDoc} */
289 @Override
290 public boolean onCreatePanelMenu(int featureId, Menu menu) {
291 return false;
292 }
293
294 /** {@inheritDoc} */
295 @Override
296 public boolean onPreparePanel(int featureId, View view, Menu menu) {
297 return false;
298 }
299
300 /** {@inheritDoc} */
301 @Override
302 public boolean onMenuOpened(int featureId, Menu menu) {
303 return false;
304 }
305
306 /** {@inheritDoc} */
307 @Override
308 public boolean onMenuItemSelected(int featureId, MenuItem item) {
309 return false;
310 }
311
312 /** {@inheritDoc} */
313 @Override
314 public void onWindowAttributesChanged(LayoutParams attrs) {
315 }
316
317 /** {@inheritDoc} */
318 @Override
319 public void onContentChanged() {
320 }
321
322 /** {@inheritDoc} */
323 @Override
324 public void onWindowFocusChanged(boolean hasFocus) {
325 }
326
327 /** {@inheritDoc} */
328 @Override
329 public void onAttachedToWindow() {
330 }
331
332 /** {@inheritDoc} */
333 @Override
334 public void onDetachedFromWindow() {
335 }
336
337 /** {@inheritDoc} */
338 @Override
339 public void onPanelClosed(int featureId, Menu menu) {
340 }
341
342 /** {@inheritDoc} */
343 @Override
Tim Kilbourn6a975b32015-04-09 17:14:34 -0700344 public boolean onSearchRequested(SearchEvent event) {
345 return onSearchRequested();
346 }
347
348 /** {@inheritDoc} */
349 @Override
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700350 public boolean onSearchRequested() {
351 return false;
352 }
353
354 /** {@inheritDoc} */
355 @Override
356 public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) {
357 return null;
358 }
359
360 /** {@inheritDoc} */
361 @Override
Clara Bayarri4423d912015-03-02 19:42:48 +0000362 public ActionMode onWindowStartingActionMode(
363 android.view.ActionMode.Callback callback, int type) {
364 return null;
365 }
366
367 /** {@inheritDoc} */
368 @Override
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700369 public void onActionModeStarted(ActionMode mode) {
370 }
371
372 /** {@inheritDoc} */
373 @Override
374 public void onActionModeFinished(ActionMode mode) {
375 }
376 // end Window.Callback methods
377
378 // begin public api
379 /**
380 * Retrieves the current {@link android.view.WindowManager} for the dream.
381 * Behaves similarly to {@link android.app.Activity#getWindowManager()}.
382 *
383 * @return The current window manager, or null if the dream is not started.
384 */
385 public WindowManager getWindowManager() {
Jeff Brown344812d2014-04-02 20:00:36 -0700386 return mWindow != null ? mWindow.getWindowManager() : null;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700387 }
388
389 /**
390 * Retrieves the current {@link android.view.Window} for the dream.
391 * Behaves similarly to {@link android.app.Activity#getWindow()}.
392 *
393 * @return The current window, or null if the dream is not started.
394 */
395 public Window getWindow() {
396 return mWindow;
397 }
398
399 /**
400 * Inflates a layout resource and set it to be the content view for this Dream.
401 * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
402 *
403 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
404 *
405 * @param layoutResID Resource ID to be inflated.
Daniel Sandler2d784902012-10-03 23:04:50 -0400406 *
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700407 * @see #setContentView(android.view.View)
408 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
409 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700410 public void setContentView(@LayoutRes int layoutResID) {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700411 getWindow().setContentView(layoutResID);
412 }
413
414 /**
415 * Sets a view to be the content view for this Dream.
Scott Main6237ac12012-10-08 22:30:29 -0700416 * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity,
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700417 * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
418 *
Scott Main6237ac12012-10-08 22:30:29 -0700419 * <p>Note: This requires a window, so you should usually call it during
420 * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
421 * during {@link #onCreate}).</p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700422 *
423 * @see #setContentView(int)
424 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
425 */
426 public void setContentView(View view) {
427 getWindow().setContentView(view);
428 }
429
430 /**
431 * Sets a view to be the content view for this Dream.
Daniel Sandler2d784902012-10-03 23:04:50 -0400432 * Behaves similarly to
Scott Main6237ac12012-10-08 22:30:29 -0700433 * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
434 * in an activity.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700435 *
Scott Main6237ac12012-10-08 22:30:29 -0700436 * <p>Note: This requires a window, so you should usually call it during
437 * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
438 * during {@link #onCreate}).</p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700439 *
440 * @param view The desired content to display.
441 * @param params Layout parameters for the view.
442 *
443 * @see #setContentView(android.view.View)
444 * @see #setContentView(int)
445 */
446 public void setContentView(View view, ViewGroup.LayoutParams params) {
447 getWindow().setContentView(view, params);
448 }
449
450 /**
451 * Adds a view to the Dream's window, leaving other content views in place.
452 *
453 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
454 *
455 * @param view The desired content to display.
456 * @param params Layout parameters for the view.
457 */
458 public void addContentView(View view, ViewGroup.LayoutParams params) {
459 getWindow().addContentView(view, params);
460 }
461
462 /**
463 * Finds a view that was identified by the id attribute from the XML that
464 * was processed in {@link #onCreate}.
465 *
466 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
Chris Craik6faa9e52018-01-11 10:46:10 -0800467 * <p>
468 * <strong>Note:</strong> In most cases -- depending on compiler support --
469 * the resulting view is automatically cast to the target class type. If
470 * the target class type is unconstrained, an explicit cast may be
471 * necessary.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700472 *
Chris Craik6faa9e52018-01-11 10:46:10 -0800473 * @param id the ID to search for
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700474 * @return The view if found or null otherwise.
Chris Craik6faa9e52018-01-11 10:46:10 -0800475 * @see View#findViewById(int)
476 * @see DreamService#requireViewById(int)
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700477 */
Scott Kennedyc0519552015-02-11 15:33:10 -0800478 @Nullable
Alan Viverette04fd4702017-04-13 16:37:06 -0400479 public <T extends View> T findViewById(@IdRes int id) {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700480 return getWindow().findViewById(id);
481 }
482
483 /**
Chris Craik6faa9e52018-01-11 10:46:10 -0800484 * Finds a view that was identified by the id attribute from the XML that was processed in
485 * {@link #onCreate}, or throws an IllegalArgumentException if the ID is invalid or there is no
486 * matching view in the hierarchy.
487 *
488 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
489 * <p>
490 * <strong>Note:</strong> In most cases -- depending on compiler support --
491 * the resulting view is automatically cast to the target class type. If
492 * the target class type is unconstrained, an explicit cast may be
493 * necessary.
494 *
495 * @param id the ID to search for
496 * @return a view with given ID
497 * @see View#requireViewById(int)
498 * @see DreamService#findViewById(int)
499 */
500 @NonNull
501 public final <T extends View> T requireViewById(@IdRes int id) {
502 T view = findViewById(id);
503 if (view == null) {
504 throw new IllegalArgumentException(
505 "ID does not reference a View inside this DreamService");
506 }
507 return view;
508 }
509
510 /**
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700511 * Marks this dream as interactive to receive input events.
512 *
513 * <p>Non-interactive dreams (default) will dismiss on the first input event.</p>
514 *
515 * <p>Interactive dreams should call {@link #finish()} to dismiss themselves.</p>
516 *
517 * @param interactive True if this dream will handle input events.
518 */
519 public void setInteractive(boolean interactive) {
520 mInteractive = interactive;
521 }
522
523 /**
524 * Returns whether or not this dream is interactive. Defaults to false.
525 *
526 * @see #setInteractive(boolean)
527 */
528 public boolean isInteractive() {
529 return mInteractive;
530 }
531
532 /**
533 * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view.
534 *
535 * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700536 * @hide There is no reason to have this -- dreams can set this flag
537 * on their own content view, and from there can actually do the
538 * correct interactions with it (seeing when it is cleared etc).
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700539 */
540 public void setLowProfile(boolean lowProfile) {
Jeff Brown26875502014-01-30 21:47:47 -0800541 if (mLowProfile != lowProfile) {
542 mLowProfile = lowProfile;
543 int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
544 applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
545 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700546 }
547
548 /**
549 * Returns whether or not this dream is in low profile mode. Defaults to true.
550 *
551 * @see #setLowProfile(boolean)
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700552 * @hide
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700553 */
554 public boolean isLowProfile() {
555 return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile);
556 }
557
558 /**
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700559 * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
560 * on the dream's window.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700561 *
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700562 * @param fullscreen If true, the fullscreen flag will be set; else it
563 * will be cleared.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700564 */
565 public void setFullscreen(boolean fullscreen) {
Jeff Brown26875502014-01-30 21:47:47 -0800566 if (mFullscreen != fullscreen) {
567 mFullscreen = fullscreen;
568 int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
569 applyWindowFlags(mFullscreen ? flag : 0, flag);
570 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700571 }
572
573 /**
574 * Returns whether or not this dream is in fullscreen mode. Defaults to false.
575 *
576 * @see #setFullscreen(boolean)
577 */
578 public boolean isFullscreen() {
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700579 return mFullscreen;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700580 }
581
582 /**
583 * Marks this dream as keeping the screen bright while dreaming.
584 *
585 * @param screenBright True to keep the screen bright while dreaming.
586 */
587 public void setScreenBright(boolean screenBright) {
Jeff Brown26875502014-01-30 21:47:47 -0800588 if (mScreenBright != screenBright) {
589 mScreenBright = screenBright;
590 int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
591 applyWindowFlags(mScreenBright ? flag : 0, flag);
592 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700593 }
594
595 /**
Jeff Brown26875502014-01-30 21:47:47 -0800596 * Returns whether or not this dream keeps the screen bright while dreaming.
597 * Defaults to false, allowing the screen to dim if necessary.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700598 *
599 * @see #setScreenBright(boolean)
600 */
601 public boolean isScreenBright() {
602 return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright);
603 }
604
605 /**
John Spurlockbf370992014-06-17 13:58:31 -0400606 * Marks this dream as windowless. Only available to doze dreams.
607 *
608 * @hide
Galia Peycheva52e89222020-02-18 23:41:43 +0100609 *
John Spurlockbf370992014-06-17 13:58:31 -0400610 */
611 public void setWindowless(boolean windowless) {
612 mWindowless = windowless;
613 }
614
615 /**
616 * Returns whether or not this dream is windowless. Only available to doze dreams.
617 *
618 * @hide
619 */
620 public boolean isWindowless() {
621 return mWindowless;
622 }
623
624 /**
Jeff Brown26875502014-01-30 21:47:47 -0800625 * Returns true if this dream is allowed to doze.
626 * <p>
627 * The value returned by this method is only meaningful when the dream has started.
628 * </p>
629 *
630 * @return True if this dream can doze.
631 * @see #startDozing
Jeff Brown970d4132014-07-19 11:33:47 -0700632 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800633 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100634 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown26875502014-01-30 21:47:47 -0800635 public boolean canDoze() {
636 return mCanDoze;
637 }
638
639 /**
640 * Starts dozing, entering a deep dreamy sleep.
641 * <p>
642 * Dozing enables the system to conserve power while the user is not actively interacting
643 * with the device. While dozing, the display will remain on in a low-power state
644 * and will continue to show its previous contents but the application processor and
645 * other system components will be allowed to suspend when possible.
646 * </p><p>
647 * While the application processor is suspended, the dream may stop executing code
648 * for long periods of time. Prior to being suspended, the dream may schedule periodic
649 * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
650 * The dream may also keep the CPU awake by acquiring a
651 * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
652 * Note that since the purpose of doze mode is to conserve power (especially when
653 * running on battery), the dream should not wake the CPU very often or keep it
654 * awake for very long.
655 * </p><p>
656 * It is a good idea to call this method some time after the dream's entry animation
657 * has completed and the dream is ready to doze. It is important to completely
658 * finish all of the work needed before dozing since the application processor may
659 * be suspended at any moment once this method is called unless other wake locks
660 * are being held.
661 * </p><p>
662 * Call {@link #stopDozing} or {@link #finish} to stop dozing.
663 * </p>
664 *
665 * @see #stopDozing
Jeff Brown970d4132014-07-19 11:33:47 -0700666 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800667 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100668 @UnsupportedAppUsage
Jeff Brown26875502014-01-30 21:47:47 -0800669 public void startDozing() {
670 if (mCanDoze && !mDozing) {
671 mDozing = true;
Jeff Brown970d4132014-07-19 11:33:47 -0700672 updateDoze();
673 }
674 }
675
676 private void updateDoze() {
Galia Peycheva6861e912019-08-21 10:20:23 +0200677 if (mDreamToken == null) {
678 Slog.w(TAG, "Updating doze without a dream token.");
Erik Wolsheimer5fb10702017-11-15 12:08:32 -0800679 return;
680 }
681
Jeff Brown970d4132014-07-19 11:33:47 -0700682 if (mDozing) {
Jeff Brown26875502014-01-30 21:47:47 -0800683 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200684 mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
Jeff Brown26875502014-01-30 21:47:47 -0800685 } catch (RemoteException ex) {
686 // system server died
687 }
688 }
689 }
690
691 /**
692 * Stops dozing, returns to active dreaming.
693 * <p>
694 * This method reverses the effect of {@link #startDozing}. From this moment onward,
695 * the application processor will be kept awake as long as the dream is running
696 * or until the dream starts dozing again.
697 * </p>
698 *
699 * @see #startDozing
Jeff Brown970d4132014-07-19 11:33:47 -0700700 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800701 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100702 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown26875502014-01-30 21:47:47 -0800703 public void stopDozing() {
704 if (mDozing) {
705 mDozing = false;
706 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200707 mDreamManager.stopDozing(mDreamToken);
Jeff Brown26875502014-01-30 21:47:47 -0800708 } catch (RemoteException ex) {
709 // system server died
710 }
711 }
712 }
713
714 /**
715 * Returns true if the dream will allow the system to enter a low-power state while
716 * it is running without actually turning off the screen. Defaults to false,
717 * keeping the application processor awake while the dream is running.
718 *
719 * @return True if the dream is dozing.
720 *
721 * @see #setDozing(boolean)
Jeff Brown970d4132014-07-19 11:33:47 -0700722 * @hide For use by system UI components only.
Jeff Brown26875502014-01-30 21:47:47 -0800723 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100724 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Brown26875502014-01-30 21:47:47 -0800725 public boolean isDozing() {
726 return mDozing;
727 }
728
729 /**
Jeff Brown970d4132014-07-19 11:33:47 -0700730 * Gets the screen state to use while dozing.
731 *
732 * @return The screen state to use while dozing, such as {@link Display#STATE_ON},
733 * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
Chris Phoenix10a4a642017-09-25 13:21:00 -0700734 * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
735 * for the default behavior.
Jeff Brown970d4132014-07-19 11:33:47 -0700736 *
737 * @see #setDozeScreenState
738 * @hide For use by system UI components only.
739 */
740 public int getDozeScreenState() {
741 return mDozeScreenState;
742 }
743
744 /**
745 * Sets the screen state to use while dozing.
746 * <p>
747 * The value of this property determines the power state of the primary display
748 * once {@link #startDozing} has been called. The default value is
749 * {@link Display#STATE_UNKNOWN} which lets the system decide.
750 * The dream may set a different state before starting to doze and may
751 * perform transitions between states while dozing to conserve power and
752 * achieve various effects.
753 * </p><p>
Chris Phoenix10a4a642017-09-25 13:21:00 -0700754 * Some devices will have dedicated hardware ("Sidekick") to animate
755 * the display content while the CPU sleeps. If the dream and the hardware support
756 * this, {@link Display#STATE_ON_SUSPEND} or {@link Display#STATE_DOZE_SUSPEND}
757 * will switch control to the Sidekick.
758 * </p><p>
759 * If not using Sidekick, it is recommended that the state be set to
760 * {@link Display#STATE_DOZE_SUSPEND} once the dream has completely
761 * finished drawing and before it releases its wakelock
762 * to allow the display hardware to be fully suspended. While suspended,
763 * the display will preserve its on-screen contents.
764 * </p><p>
765 * If the doze suspend state is used, the dream must make sure to set the mode back
Jeff Brown970d4132014-07-19 11:33:47 -0700766 * to {@link Display#STATE_DOZE} or {@link Display#STATE_ON} before drawing again
767 * since the display updates may be ignored and not seen by the user otherwise.
768 * </p><p>
769 * The set of available display power states and their behavior while dozing is
770 * hardware dependent and may vary across devices. The dream may therefore
771 * need to be modified or configured to correctly support the hardware.
772 * </p>
773 *
774 * @param state The screen state to use while dozing, such as {@link Display#STATE_ON},
775 * {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
Chris Phoenix10a4a642017-09-25 13:21:00 -0700776 * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
777 * for the default behavior.
Jeff Brown970d4132014-07-19 11:33:47 -0700778 *
779 * @hide For use by system UI components only.
780 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100781 @UnsupportedAppUsage
Jeff Brown970d4132014-07-19 11:33:47 -0700782 public void setDozeScreenState(int state) {
783 if (mDozeScreenState != state) {
784 mDozeScreenState = state;
785 updateDoze();
786 }
787 }
788
789 /**
790 * Gets the screen brightness to use while dozing.
791 *
792 * @return The screen brightness while dozing as a value between
793 * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
794 * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
795 * its default policy based on the screen state.
796 *
797 * @see #setDozeScreenBrightness
798 * @hide For use by system UI components only.
799 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100800 @UnsupportedAppUsage
Jeff Brown970d4132014-07-19 11:33:47 -0700801 public int getDozeScreenBrightness() {
802 return mDozeScreenBrightness;
803 }
804
805 /**
806 * Sets the screen brightness to use while dozing.
807 * <p>
808 * The value of this property determines the power state of the primary display
809 * once {@link #startDozing} has been called. The default value is
810 * {@link PowerManager#BRIGHTNESS_DEFAULT} which lets the system decide.
811 * The dream may set a different brightness before starting to doze and may adjust
812 * the brightness while dozing to conserve power and achieve various effects.
813 * </p><p>
814 * Note that dream may specify any brightness in the full 0-255 range, including
815 * values that are less than the minimum value for manual screen brightness
816 * adjustments by the user. In particular, the value may be set to 0 which may
817 * turn off the backlight entirely while still leaving the screen on although
818 * this behavior is device dependent and not guaranteed.
819 * </p><p>
820 * The available range of display brightness values and their behavior while dozing is
821 * hardware dependent and may vary across devices. The dream may therefore
822 * need to be modified or configured to correctly support the hardware.
823 * </p>
824 *
825 * @param brightness The screen brightness while dozing as a value between
826 * {@link PowerManager#BRIGHTNESS_OFF} (0) and {@link PowerManager#BRIGHTNESS_ON} (255),
827 * or {@link PowerManager#BRIGHTNESS_DEFAULT} (-1) to ask the system to apply
828 * its default policy based on the screen state.
829 *
830 * @hide For use by system UI components only.
831 */
Mathew Inwoode3807372018-08-10 09:51:03 +0100832 @UnsupportedAppUsage
Jeff Brown970d4132014-07-19 11:33:47 -0700833 public void setDozeScreenBrightness(int brightness) {
834 if (brightness != PowerManager.BRIGHTNESS_DEFAULT) {
835 brightness = clampAbsoluteBrightness(brightness);
836 }
837 if (mDozeScreenBrightness != brightness) {
838 mDozeScreenBrightness = brightness;
839 updateDoze();
840 }
841 }
842
843 /**
Daniel Sandler2d784902012-10-03 23:04:50 -0400844 * Called when this Dream is constructed.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700845 */
846 @Override
847 public void onCreate() {
Jeff Brown970d4132014-07-19 11:33:47 -0700848 if (mDebug) Slog.v(TAG, "onCreate()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700849 super.onCreate();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700850 }
851
852 /**
Daniel Sandler2d784902012-10-03 23:04:50 -0400853 * Called when the dream's window has been created and is visible and animation may now begin.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700854 */
Daniel Sandler2d784902012-10-03 23:04:50 -0400855 public void onDreamingStarted() {
856 if (mDebug) Slog.v(TAG, "onDreamingStarted()");
857 // hook for subclasses
858 }
859
860 /**
861 * Called when this Dream is stopped, either by external request or by calling finish(),
862 * before the window has been removed.
863 */
864 public void onDreamingStopped() {
865 if (mDebug) Slog.v(TAG, "onDreamingStopped()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700866 // hook for subclasses
867 }
868
Jeff Brownf6d46682014-07-17 22:44:20 -0700869 /**
870 * Called when the dream is being asked to stop itself and wake.
871 * <p>
872 * The default implementation simply calls {@link #finish} which ends the dream
873 * immediately. Subclasses may override this function to perform a smooth exit
874 * transition then call {@link #finish} afterwards.
875 * </p><p>
876 * Note that the dream will only be given a short period of time (currently about
877 * five seconds) to wake up. If the dream does not finish itself in a timely manner
878 * then the system will forcibly finish it once the time allowance is up.
879 * </p>
880 */
881 public void onWakeUp() {
Jerry Chang30efde62020-02-24 18:03:33 +0800882 finish();
Jeff Brownf6d46682014-07-17 22:44:20 -0700883 }
884
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700885 /** {@inheritDoc} */
886 @Override
887 public final IBinder onBind(Intent intent) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400888 if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
Galia Peycheva6861e912019-08-21 10:20:23 +0200889 mDreamServiceWrapper = new DreamServiceWrapper();
890 return mDreamServiceWrapper;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700891 }
892
893 /**
Jeff Brown26875502014-01-30 21:47:47 -0800894 * Stops the dream and detaches from the window.
895 * <p>
896 * When the dream ends, the system will be allowed to go to sleep fully unless there
897 * is a reason for it to be awake such as recent user activity or wake locks being held.
898 * </p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700899 */
Daniel Sandler2d784902012-10-03 23:04:50 -0400900 public final void finish() {
Jeff Brownf6d46682014-07-17 22:44:20 -0700901 if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished);
902
Galia Peycheva95b12342020-04-02 19:56:05 +0200903 Activity activity = mActivity;
904 if (activity != null) {
905 if (!activity.isFinishing()) {
Jerry Chang30efde62020-02-24 18:03:33 +0800906 // In case the activity is not finished yet, do it now.
Galia Peycheva95b12342020-04-02 19:56:05 +0200907 activity.finishAndRemoveTask();
Jerry Chang30efde62020-02-24 18:03:33 +0800908 }
Jerry Changb050ab82020-03-10 10:21:27 +0800909 return;
Galia Peycheva6861e912019-08-21 10:20:23 +0200910 }
911
Jerry Changb050ab82020-03-10 10:21:27 +0800912 if (mFinished) {
913 return;
914 }
915 mFinished = true;
Jeff Brownf6d46682014-07-17 22:44:20 -0700916
Jerry Changb050ab82020-03-10 10:21:27 +0800917 if (mDreamToken == null) {
918 Slog.w(TAG, "Finish was called before the dream was attached.");
919 stopSelf();
920 return;
921 }
922
923 try {
924 // finishSelf will unbind the dream controller from the dream service. This will
925 // trigger DreamService.this.onDestroy and DreamService.this will die.
926 mDreamManager.finishSelf(mDreamToken, true /*immediate*/);
927 } catch (RemoteException ex) {
928 // system server died
Jeff Brownf6d46682014-07-17 22:44:20 -0700929 }
930 }
931
932 /**
933 * Wakes the dream up gently.
934 * <p>
935 * Calls {@link #onWakeUp} to give the dream a chance to perform an exit transition.
936 * When the transition is over, the dream should call {@link #finish}.
937 * </p>
938 */
939 public final void wakeUp() {
940 wakeUp(false);
941 }
942
943 private void wakeUp(boolean fromSystem) {
944 if (mDebug) Slog.v(TAG, "wakeUp(): fromSystem=" + fromSystem
945 + ", mWaking=" + mWaking + ", mFinished=" + mFinished);
946
947 if (!mWaking && !mFinished) {
948 mWaking = true;
949
950 // As a minor optimization, invoke the callback first in case it simply
951 // calls finish() immediately so there wouldn't be much point in telling
952 // the system that we are finishing the dream gently.
953 onWakeUp();
954
955 // Now tell the system we are waking gently, unless we already told
956 // it we were finishing immediately.
957 if (!fromSystem && !mFinished) {
Galia Peycheva6861e912019-08-21 10:20:23 +0200958 if (mActivity == null) {
Jeff Brownf6d46682014-07-17 22:44:20 -0700959 Slog.w(TAG, "WakeUp was called before the dream was attached.");
960 } else {
961 try {
Galia Peycheva6861e912019-08-21 10:20:23 +0200962 mDreamManager.finishSelf(mDreamToken, false /*immediate*/);
Jeff Brownf6d46682014-07-17 22:44:20 -0700963 } catch (RemoteException ex) {
964 // system server died
965 }
966 }
967 }
968 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700969 }
970
971 /** {@inheritDoc} */
972 @Override
973 public void onDestroy() {
Daniel Sandler2d784902012-10-03 23:04:50 -0400974 if (mDebug) Slog.v(TAG, "onDestroy()");
Daniel Sandler2d784902012-10-03 23:04:50 -0400975 // hook for subclasses
Daniel Sandlerc1310702012-10-09 17:44:45 -0700976
977 // Just in case destroy came in before detach, let's take care of that now
978 detach();
979
980 super.onDestroy();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700981 }
Daniel Sandler2d784902012-10-03 23:04:50 -0400982
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700983 // end public api
984
Daniel Sandler2d784902012-10-03 23:04:50 -0400985 /**
Daniel Sandlerc1310702012-10-09 17:44:45 -0700986 * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
Daniel Sandler2d784902012-10-03 23:04:50 -0400987 *
988 * Must run on mHandler.
989 */
990 private final void detach() {
Jeff Brown344812d2014-04-02 20:00:36 -0700991 if (mStarted) {
992 if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
993 mStarted = false;
994 onDreamingStopped();
Daniel Sandler2d784902012-10-03 23:04:50 -0400995 }
996
Galia Peycheva6861e912019-08-21 10:20:23 +0200997 if (mActivity != null && !mActivity.isFinishing()) {
998 mActivity.finishAndRemoveTask();
Galia Peycheva52e89222020-02-18 23:41:43 +0100999 } else {
1000 finish();
Jeff Brown344812d2014-04-02 20:00:36 -07001001 }
Daniel Sandler2d784902012-10-03 23:04:50 -04001002
Galia Peycheva6861e912019-08-21 10:20:23 +02001003 mDreamToken = null;
1004 mCanDoze = false;
Daniel Sandler2d784902012-10-03 23:04:50 -04001005 }
1006
1007 /**
1008 * Called when the Dream is ready to be shown.
1009 *
1010 * Must run on mHandler.
1011 *
Galia Peycheva6861e912019-08-21 10:20:23 +02001012 * @param dreamToken Token for this dream service.
Adrian Roos9ede1d22016-09-23 14:08:09 -07001013 * @param started A callback that will be invoked once onDreamingStarted has completed.
Daniel Sandler2d784902012-10-03 23:04:50 -04001014 */
Galia Peycheva6861e912019-08-21 10:20:23 +02001015 private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
Jerry Chang30efde62020-02-24 18:03:33 +08001016 if (mDreamToken != null) {
Galia Peycheva6861e912019-08-21 10:20:23 +02001017 Slog.e(TAG, "attach() called when dream with token=" + mDreamToken
1018 + " already attached");
Adrian Roos9ede1d22016-09-23 14:08:09 -07001019 return;
Adrian Roos7445c0b2016-09-06 16:45:46 -07001020 }
Adrian Roos9ede1d22016-09-23 14:08:09 -07001021 if (mFinished || mWaking) {
1022 Slog.w(TAG, "attach() called after dream already finished");
1023 try {
Galia Peycheva6861e912019-08-21 10:20:23 +02001024 mDreamManager.finishSelf(dreamToken, true /*immediate*/);
Adrian Roos9ede1d22016-09-23 14:08:09 -07001025 } catch (RemoteException ex) {
1026 // system server died
1027 }
1028 return;
1029 }
1030
Galia Peycheva6861e912019-08-21 10:20:23 +02001031 mDreamToken = dreamToken;
Adrian Roos9ede1d22016-09-23 14:08:09 -07001032 mCanDoze = canDoze;
1033 if (mWindowless && !mCanDoze) {
1034 throw new IllegalStateException("Only doze dreams can be windowless");
1035 }
Adrian Roos9ede1d22016-09-23 14:08:09 -07001036
Galia Peycheva6861e912019-08-21 10:20:23 +02001037 mDispatchAfterOnAttachedToWindow = () -> {
1038 if (mWindow != null || mWindowless) {
1039 mStarted = true;
1040 try {
1041 onDreamingStarted();
1042 } finally {
Adrian Roos9ede1d22016-09-23 14:08:09 -07001043 try {
Galia Peycheva6861e912019-08-21 10:20:23 +02001044 started.sendResult(null);
1045 } catch (RemoteException e) {
1046 throw e.rethrowFromSystemServer();
Adrian Roos9ede1d22016-09-23 14:08:09 -07001047 }
1048 }
1049 }
Galia Peycheva6861e912019-08-21 10:20:23 +02001050 };
1051
1052 // We need to defer calling onDreamingStarted until after the activity is created.
1053 // If the dream is windowless, we can call it immediately. Otherwise, we wait
1054 // for the DreamActivity to report onActivityCreated via
1055 // DreamServiceWrapper.onActivityCreated.
1056 if (!mWindowless) {
1057 Intent i = new Intent(this, DreamActivity.class);
Galia Peychevaed401cc2020-03-19 20:28:09 +01001058 i.setPackage(getApplicationContext().getPackageName());
Galia Peycheva6861e912019-08-21 10:20:23 +02001059 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1060 i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
1061
1062 try {
1063 if (!ActivityTaskManager.getService().startDreamActivity(i)) {
1064 detach();
1065 return;
1066 }
1067 } catch (RemoteException e) {
1068 Log.w(TAG, "Could not connect to activity task manager to start dream activity");
1069 e.rethrowFromSystemServer();
1070 }
1071 } else {
1072 mDispatchAfterOnAttachedToWindow.run();
1073 }
1074 }
1075
1076 private void onWindowCreated(Window w) {
1077 mWindow = w;
1078 mWindow.setCallback(this);
Galia Peycheva6861e912019-08-21 10:20:23 +02001079 mWindow.requestFeature(Window.FEATURE_NO_TITLE);
1080
1081 WindowManager.LayoutParams lp = mWindow.getAttributes();
1082 lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
1083 lp.flags |= (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
1084 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
1085 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
1086 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
1087 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
1088 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
1089 | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
1090 | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
1091 );
1092 mWindow.setAttributes(lp);
1093 // Workaround: Currently low-profile and in-window system bar backgrounds don't go
1094 // along well. Dreams usually don't need such bars anyways, so disable them by default.
1095 mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
1096
1097 applySystemUiVisibilityFlags(
1098 (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
1099 View.SYSTEM_UI_FLAG_LOW_PROFILE);
1100
1101 mWindow.getDecorView().addOnAttachStateChangeListener(
1102 new View.OnAttachStateChangeListener() {
1103 @Override
1104 public void onViewAttachedToWindow(View v) {
1105 mDispatchAfterOnAttachedToWindow.run();
1106 }
1107
1108 @Override
1109 public void onViewDetachedFromWindow(View v) {
Galia Peycheva95b12342020-04-02 19:56:05 +02001110 mActivity = null;
Galia Peycheva6861e912019-08-21 10:20:23 +02001111 finish();
1112 }
1113 });
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001114 }
1115
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001116 private boolean getWindowFlagValue(int flag, boolean defaultValue) {
1117 return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0;
1118 }
1119
1120 private void applyWindowFlags(int flags, int mask) {
1121 if (mWindow != null) {
1122 WindowManager.LayoutParams lp = mWindow.getAttributes();
1123 lp.flags = applyFlags(lp.flags, flags, mask);
1124 mWindow.setAttributes(lp);
Jeff Brown344812d2014-04-02 20:00:36 -07001125 mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001126 }
1127 }
1128
1129 private boolean getSystemUiVisibilityFlagValue(int flag, boolean defaultValue) {
1130 View v = mWindow == null ? null : mWindow.getDecorView();
1131 return v == null ? defaultValue : (v.getSystemUiVisibility() & flag) != 0;
1132 }
1133
1134 private void applySystemUiVisibilityFlags(int flags, int mask) {
1135 View v = mWindow == null ? null : mWindow.getDecorView();
1136 if (v != null) {
1137 v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask));
1138 }
1139 }
1140
1141 private int applyFlags(int oldFlags, int flags, int mask) {
1142 return (oldFlags&~mask) | (flags&mask);
1143 }
1144
Daniel Sandler2d784902012-10-03 23:04:50 -04001145 @Override
John Spurlock66127272014-06-28 11:27:17 -04001146 protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) {
Jeff Brown26875502014-01-30 21:47:47 -08001147 DumpUtils.dumpAsync(mHandler, new Dump() {
1148 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001149 public void dump(PrintWriter pw, String prefix) {
John Spurlock66127272014-06-28 11:27:17 -04001150 dumpOnHandler(fd, pw, args);
Jeff Brown26875502014-01-30 21:47:47 -08001151 }
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001152 }, pw, "", 1000);
Daniel Sandler2d784902012-10-03 23:04:50 -04001153 }
1154
John Spurlock66127272014-06-28 11:27:17 -04001155 /** @hide */
1156 protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
1157 pw.print(TAG + ": ");
Galia Peycheva6861e912019-08-21 10:20:23 +02001158 if (mFinished) {
John Spurlock66127272014-06-28 11:27:17 -04001159 pw.println("stopped");
1160 } else {
Galia Peycheva6861e912019-08-21 10:20:23 +02001161 pw.println("running (dreamToken=" + mDreamToken + ")");
John Spurlock66127272014-06-28 11:27:17 -04001162 }
1163 pw.println(" window: " + mWindow);
1164 pw.print(" flags:");
1165 if (isInteractive()) pw.print(" interactive");
1166 if (isLowProfile()) pw.print(" lowprofile");
1167 if (isFullscreen()) pw.print(" fullscreen");
1168 if (isScreenBright()) pw.print(" bright");
1169 if (isWindowless()) pw.print(" windowless");
1170 if (isDozing()) pw.print(" dozing");
Jeff Brown970d4132014-07-19 11:33:47 -07001171 else if (canDoze()) pw.print(" candoze");
John Spurlock66127272014-06-28 11:27:17 -04001172 pw.println();
Jeff Brown970d4132014-07-19 11:33:47 -07001173 if (canDoze()) {
Jeff Brown970d4132014-07-19 11:33:47 -07001174 pw.println(" doze screen state: " + Display.stateToString(mDozeScreenState));
1175 pw.println(" doze screen brightness: " + mDozeScreenBrightness);
1176 }
1177 }
1178
1179 private static int clampAbsoluteBrightness(int value) {
1180 return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
John Spurlock66127272014-06-28 11:27:17 -04001181 }
1182
Galia Peycheva6861e912019-08-21 10:20:23 +02001183 /**
1184 * The DreamServiceWrapper is used as a gateway to the system_server, where DreamController
1185 * uses it to control the DreamService. It is also used to receive callbacks from the
1186 * DreamActivity.
1187 */
1188 final class DreamServiceWrapper extends IDreamService.Stub {
Jeff Brown26875502014-01-30 21:47:47 -08001189 @Override
Galia Peycheva6861e912019-08-21 10:20:23 +02001190 public void attach(final IBinder dreamToken, final boolean canDoze,
Adrian Roos9ede1d22016-09-23 14:08:09 -07001191 IRemoteCallback started) {
Galia Peycheva6861e912019-08-21 10:20:23 +02001192 mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started));
Daniel Sandler2d784902012-10-03 23:04:50 -04001193 }
Jeff Brown26875502014-01-30 21:47:47 -08001194
1195 @Override
Daniel Sandler2d784902012-10-03 23:04:50 -04001196 public void detach() {
Galia Peychevaa8e464122020-02-14 19:00:29 +01001197 mHandler.post(DreamService.this::detach);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001198 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001199
Jeff Brownf6d46682014-07-17 22:44:20 -07001200 @Override
1201 public void wakeUp() {
Galia Peychevaa8e464122020-02-14 19:00:29 +01001202 mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
Jeff Brownf6d46682014-07-17 22:44:20 -07001203 }
Galia Peycheva6861e912019-08-21 10:20:23 +02001204
1205 /** @hide */
1206 void onActivityCreated(DreamActivity a) {
1207 mActivity = a;
1208 onWindowCreated(a.getWindow());
1209 }
Jeff Brownf6d46682014-07-17 22:44:20 -07001210 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -07001211}