blob: cb78763a6937ec2ce0a6496731849eb216a70c2d [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
Daniel Sandler2d784902012-10-03 23:04:50 -040018import java.io.FileDescriptor;
19import java.io.PrintWriter;
20
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070021import android.annotation.SdkConstant;
22import android.annotation.SdkConstant.SdkConstantType;
23import android.app.Service;
24import android.content.Intent;
Dianne Hackborn4c1e3182012-10-05 18:37:54 -070025import android.graphics.PixelFormat;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070026import android.graphics.drawable.ColorDrawable;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.ServiceManager;
30import android.util.Slog;
31import android.view.ActionMode;
32import android.view.KeyEvent;
33import android.view.Menu;
34import android.view.MenuItem;
35import android.view.MotionEvent;
36import android.view.View;
37import android.view.ViewGroup;
38import android.view.Window;
39import android.view.WindowManager;
40import android.view.WindowManager.LayoutParams;
41import android.view.accessibility.AccessibilityEvent;
42
43import com.android.internal.policy.PolicyManager;
44
45/**
Daniel Sandler2d784902012-10-03 23:04:50 -040046 * Extend this class to implement a custom Dream (displayed to the user as a "Sleep Mode").
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070047 *
48 * <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a
49 * desk dock. Dreams provide another modality for apps to express themselves, tailored for
50 * an exhibition/lean-back experience.</p>
51 *
Daniel Sandler2d784902012-10-03 23:04:50 -040052 * <p>The Dream lifecycle is as follows:</p>
53 * <ul>
54 * <li>onAttachedToWindow</li>
55 * <li>onDreamingStarted</li>
56 * <li>onDreamingStopped</li>
57 * <li>onDetachedFromWindow</li>
58 * </ul>
59 *
60 * <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
61 * initialization and teardown should be done by overriding the hooks above.</p>
62 *
63 * <p>To be available to the system, Dreams should be declared in the manifest as follows:</p>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070064 * <pre>
John Spurlock3a4d41a2012-10-01 09:30:49 -040065 * &lt;service
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070066 * android:name=".MyDream"
67 * android:exported="true"
68 * android:icon="@drawable/my_icon"
69 * android:label="@string/my_dream_label" >
70 *
John Spurlock3a4d41a2012-10-01 09:30:49 -040071 * &lt;intent-filter>
72 * &lt;action android:name="android.service.dreams.DreamService" />
73 * &lt;category android:name="android.intent.category.DEFAULT" />
74 * &lt;/intent-filter>
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070075 *
John Spurlock3a4d41a2012-10-01 09:30:49 -040076 * &lt;!-- Point to additional information for this dream (optional) -->
77 * &lt;meta-data
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070078 * android:name="android.service.dream"
79 * android:resource="@xml/my_dream" />
John Spurlock3a4d41a2012-10-01 09:30:49 -040080 * &lt;/service>
81 * </pre>
82 * <p>If specified, additional information for the dream is defined using the
83 * <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code> element. For example:</p>
84 * <pre>
85 * (in res/xml/my_dream.xml)
86 *
87 * &lt;dream xmlns:android="http://schemas.android.com/apk/res/android"
88 * android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070089 * </pre>
90 */
91public class DreamService extends Service implements Window.Callback {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -070092 private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
93
94 /**
95 * The name of the dream manager service.
96 * @hide
97 */
98 public static final String DREAM_SERVICE = "dreams";
99
100 /**
101 * The {@link Intent} that must be declared as handled by the service.
102 */
103 @SdkConstant(SdkConstantType.SERVICE_ACTION)
104 public static final String SERVICE_INTERFACE =
105 "android.service.dreams.DreamService";
106
107 /**
108 * Name under which a Dream publishes information about itself.
109 * This meta-data must reference an XML resource containing
110 * a <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code>
111 * tag.
112 */
113 public static final String DREAM_META_DATA = "android.service.dream";
114
115 private final Handler mHandler = new Handler();
116 private IBinder mWindowToken;
117 private Window mWindow;
118 private WindowManager mWindowManager;
119 private IDreamManager mSandman;
120 private boolean mInteractive = false;
121 private boolean mLowProfile = true;
122 private boolean mFullscreen = false;
123 private boolean mScreenBright = false;
124 private boolean mFinished;
125
Daniel Sandler2d784902012-10-03 23:04:50 -0400126 private boolean mDebug = false;
127
128 /**
129 * @hide
130 */
131 public void setDebug(boolean dbg) {
132 mDebug = dbg;
133 }
134
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700135 // begin Window.Callback methods
136 /** {@inheritDoc} */
137 @Override
138 public boolean dispatchKeyEvent(KeyEvent event) {
139 // TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK
140 if (!mInteractive) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400141 if (mDebug) Slog.v(TAG, "Finishing on keyEvent");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700142 safelyFinish();
143 return true;
144 } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400145 if (mDebug) Slog.v(TAG, "Finishing on back key");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700146 safelyFinish();
147 return true;
148 }
149 return mWindow.superDispatchKeyEvent(event);
150 }
151
152 /** {@inheritDoc} */
153 @Override
154 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400155 if (!mInteractive) {
156 if (mDebug) Slog.v(TAG, "Finishing on keyShortcutEvent");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700157 safelyFinish();
158 return true;
159 }
160 return mWindow.superDispatchKeyShortcutEvent(event);
161 }
162
163 /** {@inheritDoc} */
164 @Override
165 public boolean dispatchTouchEvent(MotionEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400166 // TODO: create more flexible version of mInteractive that allows clicks
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700167 // but finish()es on any other kind of activity
Daniel Sandler2d784902012-10-03 23:04:50 -0400168 if (!mInteractive) {
169 if (mDebug) Slog.v(TAG, "Finishing on touchEvent");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700170 safelyFinish();
171 return true;
172 }
173 return mWindow.superDispatchTouchEvent(event);
174 }
175
176 /** {@inheritDoc} */
177 @Override
178 public boolean dispatchTrackballEvent(MotionEvent event) {
179 if (!mInteractive) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400180 if (mDebug) Slog.v(TAG, "Finishing on trackballEvent");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700181 safelyFinish();
182 return true;
183 }
184 return mWindow.superDispatchTrackballEvent(event);
185 }
186
187 /** {@inheritDoc} */
188 @Override
189 public boolean dispatchGenericMotionEvent(MotionEvent event) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400190 if (!mInteractive) {
191 if (mDebug) Slog.v(TAG, "Finishing on genericMotionEvent");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700192 safelyFinish();
193 return true;
194 }
195 return mWindow.superDispatchGenericMotionEvent(event);
196 }
197
198 /** {@inheritDoc} */
199 @Override
200 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
201 return false;
202 }
203
204 /** {@inheritDoc} */
205 @Override
206 public View onCreatePanelView(int featureId) {
207 return null;
208 }
209
210 /** {@inheritDoc} */
211 @Override
212 public boolean onCreatePanelMenu(int featureId, Menu menu) {
213 return false;
214 }
215
216 /** {@inheritDoc} */
217 @Override
218 public boolean onPreparePanel(int featureId, View view, Menu menu) {
219 return false;
220 }
221
222 /** {@inheritDoc} */
223 @Override
224 public boolean onMenuOpened(int featureId, Menu menu) {
225 return false;
226 }
227
228 /** {@inheritDoc} */
229 @Override
230 public boolean onMenuItemSelected(int featureId, MenuItem item) {
231 return false;
232 }
233
234 /** {@inheritDoc} */
235 @Override
236 public void onWindowAttributesChanged(LayoutParams attrs) {
237 }
238
239 /** {@inheritDoc} */
240 @Override
241 public void onContentChanged() {
242 }
243
244 /** {@inheritDoc} */
245 @Override
246 public void onWindowFocusChanged(boolean hasFocus) {
247 }
248
249 /** {@inheritDoc} */
250 @Override
251 public void onAttachedToWindow() {
252 }
253
254 /** {@inheritDoc} */
255 @Override
256 public void onDetachedFromWindow() {
257 }
258
259 /** {@inheritDoc} */
260 @Override
261 public void onPanelClosed(int featureId, Menu menu) {
262 }
263
264 /** {@inheritDoc} */
265 @Override
266 public boolean onSearchRequested() {
267 return false;
268 }
269
270 /** {@inheritDoc} */
271 @Override
272 public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) {
273 return null;
274 }
275
276 /** {@inheritDoc} */
277 @Override
278 public void onActionModeStarted(ActionMode mode) {
279 }
280
281 /** {@inheritDoc} */
282 @Override
283 public void onActionModeFinished(ActionMode mode) {
284 }
285 // end Window.Callback methods
286
287 // begin public api
288 /**
289 * Retrieves the current {@link android.view.WindowManager} for the dream.
290 * Behaves similarly to {@link android.app.Activity#getWindowManager()}.
291 *
292 * @return The current window manager, or null if the dream is not started.
293 */
294 public WindowManager getWindowManager() {
295 return mWindowManager;
296 }
297
298 /**
299 * Retrieves the current {@link android.view.Window} for the dream.
300 * Behaves similarly to {@link android.app.Activity#getWindow()}.
301 *
302 * @return The current window, or null if the dream is not started.
303 */
304 public Window getWindow() {
305 return mWindow;
306 }
307
308 /**
309 * Inflates a layout resource and set it to be the content view for this Dream.
310 * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
311 *
312 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
313 *
314 * @param layoutResID Resource ID to be inflated.
Daniel Sandler2d784902012-10-03 23:04:50 -0400315 *
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700316 * @see #setContentView(android.view.View)
317 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
318 */
319 public void setContentView(int layoutResID) {
320 getWindow().setContentView(layoutResID);
321 }
322
323 /**
324 * Sets a view to be the content view for this Dream.
325 * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
326 * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
327 *
328 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
329 * @param view The desired content to display.
330 *
331 * @see #setContentView(int)
332 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
333 */
334 public void setContentView(View view) {
335 getWindow().setContentView(view);
336 }
337
338 /**
339 * Sets a view to be the content view for this Dream.
Daniel Sandler2d784902012-10-03 23:04:50 -0400340 * Behaves similarly to
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700341 * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
342 *
343 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
344 *
345 * @param view The desired content to display.
346 * @param params Layout parameters for the view.
347 *
348 * @see #setContentView(android.view.View)
349 * @see #setContentView(int)
350 */
351 public void setContentView(View view, ViewGroup.LayoutParams params) {
352 getWindow().setContentView(view, params);
353 }
354
355 /**
356 * Adds a view to the Dream's window, leaving other content views in place.
357 *
358 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
359 *
360 * @param view The desired content to display.
361 * @param params Layout parameters for the view.
362 */
363 public void addContentView(View view, ViewGroup.LayoutParams params) {
364 getWindow().addContentView(view, params);
365 }
366
367 /**
368 * Finds a view that was identified by the id attribute from the XML that
369 * was processed in {@link #onCreate}.
370 *
371 * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
372 *
373 * @return The view if found or null otherwise.
374 */
375 public View findViewById(int id) {
376 return getWindow().findViewById(id);
377 }
378
379 /**
380 * Marks this dream as interactive to receive input events.
381 *
382 * <p>Non-interactive dreams (default) will dismiss on the first input event.</p>
383 *
384 * <p>Interactive dreams should call {@link #finish()} to dismiss themselves.</p>
385 *
386 * @param interactive True if this dream will handle input events.
387 */
388 public void setInteractive(boolean interactive) {
389 mInteractive = interactive;
390 }
391
392 /**
393 * Returns whether or not this dream is interactive. Defaults to false.
394 *
395 * @see #setInteractive(boolean)
396 */
397 public boolean isInteractive() {
398 return mInteractive;
399 }
400
401 /**
402 * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view.
403 *
404 * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700405 * @hide There is no reason to have this -- dreams can set this flag
406 * on their own content view, and from there can actually do the
407 * correct interactions with it (seeing when it is cleared etc).
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700408 */
409 public void setLowProfile(boolean lowProfile) {
410 mLowProfile = lowProfile;
411 int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
412 applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
413 }
414
415 /**
416 * Returns whether or not this dream is in low profile mode. Defaults to true.
417 *
418 * @see #setLowProfile(boolean)
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700419 * @hide
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700420 */
421 public boolean isLowProfile() {
422 return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile);
423 }
424
425 /**
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700426 * Controls {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
427 * on the dream's window.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700428 *
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700429 * @param fullscreen If true, the fullscreen flag will be set; else it
430 * will be cleared.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700431 */
432 public void setFullscreen(boolean fullscreen) {
433 mFullscreen = fullscreen;
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700434 int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
435 applyWindowFlags(mFullscreen ? flag : 0, flag);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700436 }
437
438 /**
439 * Returns whether or not this dream is in fullscreen mode. Defaults to false.
440 *
441 * @see #setFullscreen(boolean)
442 */
443 public boolean isFullscreen() {
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700444 return mFullscreen;
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700445 }
446
447 /**
448 * Marks this dream as keeping the screen bright while dreaming.
449 *
450 * @param screenBright True to keep the screen bright while dreaming.
451 */
452 public void setScreenBright(boolean screenBright) {
453 mScreenBright = screenBright;
454 int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
455 applyWindowFlags(mScreenBright ? flag : 0, flag);
456 }
457
458 /**
459 * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
460 * allowing the screen to dim if necessary.
461 *
462 * @see #setScreenBright(boolean)
463 */
464 public boolean isScreenBright() {
465 return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright);
466 }
467
468 /**
Daniel Sandler2d784902012-10-03 23:04:50 -0400469 * Called when this Dream is constructed.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700470 */
471 @Override
472 public void onCreate() {
Daniel Sandler2d784902012-10-03 23:04:50 -0400473 if (mDebug) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId());
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700474 super.onCreate();
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700475 }
476
477 /**
Daniel Sandler2d784902012-10-03 23:04:50 -0400478 * Called when the dream's window has been created and is visible and animation may now begin.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700479 */
Daniel Sandler2d784902012-10-03 23:04:50 -0400480 public void onDreamingStarted() {
481 if (mDebug) Slog.v(TAG, "onDreamingStarted()");
482 // hook for subclasses
483 }
484
485 /**
486 * Called when this Dream is stopped, either by external request or by calling finish(),
487 * before the window has been removed.
488 */
489 public void onDreamingStopped() {
490 if (mDebug) Slog.v(TAG, "onDreamingStopped()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700491 // hook for subclasses
492 }
493
494 /** {@inheritDoc} */
495 @Override
496 public final IBinder onBind(Intent intent) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400497 if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700498 return new DreamServiceWrapper();
499 }
500
501 /**
502 * Stops the dream, detaches from the window, and wakes up.
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700503 */
Daniel Sandler2d784902012-10-03 23:04:50 -0400504 public final void finish() {
505 if (mDebug) Slog.v(TAG, "finish()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700506 finishInternal();
507 }
508
509 /** {@inheritDoc} */
510 @Override
511 public void onDestroy() {
Daniel Sandler2d784902012-10-03 23:04:50 -0400512 if (mDebug) Slog.v(TAG, "onDestroy()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700513 super.onDestroy();
Daniel Sandler2d784902012-10-03 23:04:50 -0400514 // hook for subclasses
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700515 }
Daniel Sandler2d784902012-10-03 23:04:50 -0400516
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700517 // end public api
518
519 private void loadSandman() {
520 mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
521 }
522
Daniel Sandler2d784902012-10-03 23:04:50 -0400523 /**
524 * Called when the Dream is about to be unbound and destroyed.
525 *
526 * Must run on mHandler.
527 */
528 private final void detach() {
529 if (mWindow == null) {
530 Slog.e(TAG, "detach() called when not attached");
531 return;
532 }
533
534 try {
535 onDreamingStopped();
536 } catch (Throwable t) {
537 Slog.w(TAG, "Crashed in onDreamingStopped()", t);
538 // we were going to stop anyway
539 }
540
541 if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
542 try {
543 mWindowManager.removeView(mWindow.getDecorView());
544 } catch (Throwable t) {
545 Slog.w(TAG, "Crashed removing window view", t);
546 }
547
548 mWindow = null;
549 mWindowToken = null;
550 }
551
552 /**
553 * Called when the Dream is ready to be shown.
554 *
555 * Must run on mHandler.
556 *
557 * @param windowToken A window token that will allow a window to be created in the correct layer.
558 */
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700559 private final void attach(IBinder windowToken) {
Daniel Sandler2d784902012-10-03 23:04:50 -0400560 if (mWindowToken != null) {
561 Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
562 return;
563 }
564
565 if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700566
567 if (mSandman == null) {
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700568 loadSandman();
569 }
570 mWindowToken = windowToken;
571 mWindow = PolicyManager.makeNewWindow(this);
572 mWindow.setCallback(this);
573 mWindow.requestFeature(Window.FEATURE_NO_TITLE);
574 mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700575 mWindow.setFormat(PixelFormat.OPAQUE);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700576
Daniel Sandler2d784902012-10-03 23:04:50 -0400577 if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700578 windowToken, WindowManager.LayoutParams.TYPE_DREAM));
579
580 WindowManager.LayoutParams lp = mWindow.getAttributes();
581 lp.type = WindowManager.LayoutParams.TYPE_DREAM;
582 lp.token = windowToken;
583 lp.windowAnimations = com.android.internal.R.style.Animation_Dream;
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700584 lp.flags |= ( WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
585 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
586 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700587 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
588 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700589 | (mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0)
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700590 | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
591 );
592 mWindow.setAttributes(lp);
593
Daniel Sandler2d784902012-10-03 23:04:50 -0400594 if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700595
596 mWindow.setWindowManager(null, windowToken, "dream", true);
597 mWindowManager = mWindow.getWindowManager();
598
Daniel Sandler2d784902012-10-03 23:04:50 -0400599 if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
600 try {
601 applySystemUiVisibilityFlags(
Dianne Hackborn4c1e3182012-10-05 18:37:54 -0700602 (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
603 View.SYSTEM_UI_FLAG_LOW_PROFILE);
Daniel Sandler2d784902012-10-03 23:04:50 -0400604 getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
605 } catch (Throwable t) {
606 Slog.w("Crashed adding window view", t);
607 safelyFinish();
608 return;
609 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700610
Daniel Sandler2d784902012-10-03 23:04:50 -0400611 // start it up
612 try {
613 onDreamingStarted();
614 } catch (Throwable t) {
615 Slog.w("Crashed in onDreamingStarted()", t);
616 safelyFinish();
617 }
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700618 }
619
620 private void safelyFinish() {
Daniel Sandler2d784902012-10-03 23:04:50 -0400621 if (mDebug) Slog.v(TAG, "safelyFinish()");
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700622 try {
623 finish();
624 } catch (Throwable t) {
625 Slog.w(TAG, "Crashed in safelyFinish()", t);
626 finishInternal();
627 return;
628 }
629
630 if (!mFinished) {
631 Slog.w(TAG, "Bad dream, did not call super.finish()");
632 finishInternal();
633 }
634 }
635
636 private void finishInternal() {
Daniel Sandler2d784902012-10-03 23:04:50 -0400637 if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700638 if (mFinished) return;
639 try {
640 mFinished = true;
641
642 if (mSandman != null) {
643 mSandman.finishSelf(mWindowToken);
644 } else {
645 Slog.w(TAG, "No dream manager found");
646 }
647 stopSelf(); // if launched via any other means
648
649 } catch (Throwable t) {
650 Slog.w(TAG, "Crashed in finishInternal()", t);
651 }
652 }
653
654 private boolean getWindowFlagValue(int flag, boolean defaultValue) {
655 return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0;
656 }
657
658 private void applyWindowFlags(int flags, int mask) {
659 if (mWindow != null) {
660 WindowManager.LayoutParams lp = mWindow.getAttributes();
661 lp.flags = applyFlags(lp.flags, flags, mask);
662 mWindow.setAttributes(lp);
663 mWindowManager.updateViewLayout(mWindow.getDecorView(), lp);
664 }
665 }
666
667 private boolean getSystemUiVisibilityFlagValue(int flag, boolean defaultValue) {
668 View v = mWindow == null ? null : mWindow.getDecorView();
669 return v == null ? defaultValue : (v.getSystemUiVisibility() & flag) != 0;
670 }
671
672 private void applySystemUiVisibilityFlags(int flags, int mask) {
673 View v = mWindow == null ? null : mWindow.getDecorView();
674 if (v != null) {
675 v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask));
676 }
677 }
678
679 private int applyFlags(int oldFlags, int flags, int mask) {
680 return (oldFlags&~mask) | (flags&mask);
681 }
682
Daniel Sandler2d784902012-10-03 23:04:50 -0400683 @Override
684 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
685 super.dump(fd, pw, args);
686
687 pw.print(TAG + ": ");
688 if (mWindowToken == null) {
689 pw.println("stopped");
690 } else {
691 pw.println("running (token=" + mWindowToken + ")");
692 }
693 pw.println(" window: " + mWindow);
694 pw.print(" flags:");
695 if (isInteractive()) pw.print(" interactive");
696 if (isLowProfile()) pw.print(" lowprofile");
697 if (isFullscreen()) pw.print(" fullscreen");
698 if (isScreenBright()) pw.print(" bright");
699 pw.println();
700 }
701
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700702 private class DreamServiceWrapper extends IDreamService.Stub {
Daniel Sandler2d784902012-10-03 23:04:50 -0400703 public void attach(final IBinder windowToken) {
704 mHandler.post(new Runnable() {
705 @Override
706 public void run() {
707 DreamService.this.attach(windowToken);
708 }
709 });
710 }
711 public void detach() {
712 mHandler.post(new Runnable() {
713 @Override
714 public void run() {
715 DreamService.this.detach();
716 }
717 });
Dianne Hackbornbe87e2f2012-09-28 16:31:34 -0700718 }
719 }
720
721}