diff --git a/api/current.txt b/api/current.txt index ab4579045106e..1de68edc708ed 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5777,6 +5777,8 @@ package android.content { field public static final java.lang.String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK"; field public static final java.lang.String ACTION_DIAL = "android.intent.action.DIAL"; field public static final java.lang.String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT"; + field public static final java.lang.String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED"; + field public static final java.lang.String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED"; field public static final java.lang.String ACTION_EDIT = "android.intent.action.EDIT"; field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE"; field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE"; @@ -20317,8 +20319,8 @@ package android.security { package android.service.dreams { - public class Dream extends android.app.Service implements android.view.Window.Callback { - ctor public Dream(); + public class DreamService extends android.app.Service implements android.view.Window.Callback { + ctor public DreamService(); method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams); method public boolean dispatchGenericMotionEvent(android.view.MotionEvent); method public boolean dispatchKeyEvent(android.view.KeyEvent); @@ -20358,10 +20360,8 @@ package android.service.dreams { method public void setInteractive(boolean); method public void setLowProfile(boolean); method public void setScreenBright(boolean); - field public static final java.lang.String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED"; - field public static final java.lang.String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED"; - field public static final java.lang.String CATEGORY_DREAM = "android.intent.category.DREAM"; field public static final java.lang.String DREAM_META_DATA = "android.service.dream"; + field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService"; } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c301c5c2b9e08..d4f6c06479ba8 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1389,6 +1389,24 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON"; + /** + * Broadcast Action: Sent after the system stops dreaming. + * + *

This is a protected intent that can only be sent by the system. + * It is only sent to registered receivers.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED"; + + /** + * Broadcast Action: Sent after the system starts dreaming. + * + *

This is a protected intent that can only be sent by the system. + * It is only sent to registered receivers.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED"; + /** * Broadcast Action: Sent when the user is present after device wakes up (e.g when the * keyguard is gone). diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java index 590acfad680cd..4e8b05bff493c 100644 --- a/core/java/android/service/dreams/Dream.java +++ b/core/java/android/service/dreams/Dream.java @@ -15,625 +15,9 @@ */ package android.service.dreams; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.app.Service; -import android.content.Intent; -import android.graphics.drawable.ColorDrawable; -import android.os.Handler; -import android.os.IBinder; -import android.os.ServiceManager; -import android.util.Slog; -import android.view.ActionMode; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.view.accessibility.AccessibilityEvent; - -import com.android.internal.policy.PolicyManager; - /** - * Extend this class to implement a custom Dream. - * - *

Dreams are interactive screensavers launched when a charging device is idle, or docked in a - * desk dock. Dreams provide another modality for apps to express themselves, tailored for - * an exhibition/lean-back experience.

- * - *

Dreams should be declared in the manifest as follows:

- *
- * {@code
- * 
- *
- *     
- *         
- *         
- *     
- *
- *     
- *     
- * 
- * }
- * 
+ * @hide + * Temporarily needed to not break existing apps. */ -public class Dream extends Service implements Window.Callback { - private final static boolean DEBUG = true; - private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; - - /** - * The name of the dream manager service. - * @hide - */ - public static final String DREAM_SERVICE = "dreams"; - - /** - * Used with {@link Intent#ACTION_MAIN} to declare the necessary intent-filter for a dream. - * - * @see Dream - */ - @SdkConstant(SdkConstantType.INTENT_CATEGORY) - public static final String CATEGORY_DREAM = - "android.intent.category.DREAM"; - - /** - * Name under which a Dream publishes information about itself. - * This meta-data must reference an XML resource containing - * a <{@link android.R.styleable#Dream dream}> - * tag. - */ - public static final String DREAM_META_DATA = "android.service.dream"; - - /** - * Broadcast Action: Sent after the system starts dreaming. - * - *

This is a protected intent that can only be sent by the system. - * It is only sent to registered receivers.

- */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED"; - - /** - * Broadcast Action: Sent after the system stops dreaming. - * - *

This is a protected intent that can only be sent by the system. - * It is only sent to registered receivers.

- */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED"; - - private final Handler mHandler = new Handler(); - private IBinder mWindowToken; - private Window mWindow; - private WindowManager mWindowManager; - private IDreamManager mSandman; - private boolean mInteractive = false; - private boolean mLowProfile = true; - private boolean mFullscreen = false; - private boolean mScreenBright = false; - private boolean mFinished; - - // begin Window.Callback methods - /** {@inheritDoc} */ - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - // TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK - if (!mInteractive) { - if (DEBUG) Slog.v(TAG, "Finishing on keyEvent"); - safelyFinish(); - return true; - } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { - if (DEBUG) Slog.v(TAG, "Finishing on back key"); - safelyFinish(); - return true; - } - return mWindow.superDispatchKeyEvent(event); - } - - /** {@inheritDoc} */ - @Override - public boolean dispatchKeyShortcutEvent(KeyEvent event) { - if (!mInteractive) { - if (DEBUG) Slog.v(TAG, "Finishing on keyShortcutEvent"); - safelyFinish(); - return true; - } - return mWindow.superDispatchKeyShortcutEvent(event); - } - - /** {@inheritDoc} */ - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - // TODO: create more flexible version of mInteractive that allows clicks - // but finish()es on any other kind of activity - if (!mInteractive) { - if (DEBUG) Slog.v(TAG, "Finishing on touchEvent"); - safelyFinish(); - return true; - } - return mWindow.superDispatchTouchEvent(event); - } - - /** {@inheritDoc} */ - @Override - public boolean dispatchTrackballEvent(MotionEvent event) { - if (!mInteractive) { - if (DEBUG) Slog.v(TAG, "Finishing on trackballEvent"); - safelyFinish(); - return true; - } - return mWindow.superDispatchTrackballEvent(event); - } - - /** {@inheritDoc} */ - @Override - public boolean dispatchGenericMotionEvent(MotionEvent event) { - if (!mInteractive) { - if (DEBUG) Slog.v(TAG, "Finishing on genericMotionEvent"); - safelyFinish(); - return true; - } - return mWindow.superDispatchGenericMotionEvent(event); - } - - /** {@inheritDoc} */ - @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - return false; - } - - /** {@inheritDoc} */ - @Override - public View onCreatePanelView(int featureId) { - return null; - } - - /** {@inheritDoc} */ - @Override - public boolean onCreatePanelMenu(int featureId, Menu menu) { - return false; - } - - /** {@inheritDoc} */ - @Override - public boolean onPreparePanel(int featureId, View view, Menu menu) { - return false; - } - - /** {@inheritDoc} */ - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - return false; - } - - /** {@inheritDoc} */ - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - return false; - } - - /** {@inheritDoc} */ - @Override - public void onWindowAttributesChanged(LayoutParams attrs) { - } - - /** {@inheritDoc} */ - @Override - public void onContentChanged() { - } - - /** {@inheritDoc} */ - @Override - public void onWindowFocusChanged(boolean hasFocus) { - } - - /** {@inheritDoc} */ - @Override - public void onAttachedToWindow() { - } - - /** {@inheritDoc} */ - @Override - public void onDetachedFromWindow() { - } - - /** {@inheritDoc} */ - @Override - public void onPanelClosed(int featureId, Menu menu) { - } - - /** {@inheritDoc} */ - @Override - public boolean onSearchRequested() { - return false; - } - - /** {@inheritDoc} */ - @Override - public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) { - return null; - } - - /** {@inheritDoc} */ - @Override - public void onActionModeStarted(ActionMode mode) { - } - - /** {@inheritDoc} */ - @Override - public void onActionModeFinished(ActionMode mode) { - } - // end Window.Callback methods - - // begin public api - /** - * Retrieves the current {@link android.view.WindowManager} for the dream. - * Behaves similarly to {@link android.app.Activity#getWindowManager()}. - * - * @return The current window manager, or null if the dream is not started. - */ - public WindowManager getWindowManager() { - return mWindowManager; - } - - /** - * Retrieves the current {@link android.view.Window} for the dream. - * Behaves similarly to {@link android.app.Activity#getWindow()}. - * - * @return The current window, or null if the dream is not started. - */ - public Window getWindow() { - return mWindow; - } - - /** - * Inflates a layout resource and set it to be the content view for this Dream. - * Behaves similarly to {@link android.app.Activity#setContentView(int)}. - * - *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

- * - * @param layoutResID Resource ID to be inflated. - * - * @see #setContentView(android.view.View) - * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) - */ - public void setContentView(int layoutResID) { - getWindow().setContentView(layoutResID); - } - - /** - * Sets a view to be the content view for this Dream. - * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)}, - * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view. - * - *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

- * @param view The desired content to display. - * - * @see #setContentView(int) - * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) - */ - public void setContentView(View view) { - getWindow().setContentView(view); - } - - /** - * Sets a view to be the content view for this Dream. - * Behaves similarly to - * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}. - * - *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

- * - * @param view The desired content to display. - * @param params Layout parameters for the view. - * - * @see #setContentView(android.view.View) - * @see #setContentView(int) - */ - public void setContentView(View view, ViewGroup.LayoutParams params) { - getWindow().setContentView(view, params); - } - - /** - * Adds a view to the Dream's window, leaving other content views in place. - * - *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

- * - * @param view The desired content to display. - * @param params Layout parameters for the view. - */ - public void addContentView(View view, ViewGroup.LayoutParams params) { - getWindow().addContentView(view, params); - } - - /** - * Finds a view that was identified by the id attribute from the XML that - * was processed in {@link #onCreate}. - * - *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

- * - * @return The view if found or null otherwise. - */ - public View findViewById(int id) { - return getWindow().findViewById(id); - } - - /** - * Marks this dream as interactive to receive input events. - * - *

Non-interactive dreams (default) will dismiss on the first input event.

- * - *

Interactive dreams should call {@link #finish()} to dismiss themselves.

- * - * @param interactive True if this dream will handle input events. - */ - public void setInteractive(boolean interactive) { - mInteractive = interactive; - } - - /** - * Returns whether or not this dream is interactive. Defaults to false. - * - * @see #setInteractive(boolean) - */ - public boolean isInteractive() { - return mInteractive; - } - - /** - * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. - * - * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE - */ - public void setLowProfile(boolean lowProfile) { - mLowProfile = lowProfile; - int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE; - applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag); - } - - /** - * Returns whether or not this dream is in low profile mode. Defaults to true. - * - * @see #setLowProfile(boolean) - */ - public boolean isLowProfile() { - return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile); - } - - /** - * Sets View.SYSTEM_UI_FLAG_FULLSCREEN on the content view. - * - * @param fullscreen True to set View.SYSTEM_UI_FLAG_FULLSCREEN - */ - public void setFullscreen(boolean fullscreen) { - mFullscreen = fullscreen; - int flag = View.SYSTEM_UI_FLAG_FULLSCREEN; - applySystemUiVisibilityFlags(mFullscreen ? flag : 0, flag); - } - - /** - * Returns whether or not this dream is in fullscreen mode. Defaults to false. - * - * @see #setFullscreen(boolean) - */ - public boolean isFullscreen() { - return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_FULLSCREEN, mFullscreen); - } - - /** - * Marks this dream as keeping the screen bright while dreaming. - * - * @param screenBright True to keep the screen bright while dreaming. - */ - public void setScreenBright(boolean screenBright) { - mScreenBright = screenBright; - int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - applyWindowFlags(mScreenBright ? flag : 0, flag); - } - - /** - * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false, - * allowing the screen to dim if necessary. - * - * @see #setScreenBright(boolean) - */ - public boolean isScreenBright() { - return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright); - } - - /** - * Called when this Dream is constructed. Place your initialization here. - * - *

Subclasses must call through to the superclass implementation.

- */ - @Override - public void onCreate() { - if (DEBUG) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId()); - super.onCreate(); - loadSandman(); - } - - /** - * Called when this Dream is started. The window is created and visible at this point. - */ - public void onStart() { - if (DEBUG) Slog.v(TAG, "onStart()"); - // hook for subclasses - } - - /** {@inheritDoc} */ - @Override - public final IBinder onBind(Intent intent) { - if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); - return new DreamServiceWrapper(); - } - - /** - * Stops the dream, detaches from the window, and wakes up. - * - *

Subclasses must call through to the superclass implementation.

- * - *

After this method is called, the service will be stopped.

- */ - public void finish() { - if (DEBUG) Slog.v(TAG, "finish()"); - finishInternal(); - } - - /** {@inheritDoc} */ - @Override - public void onDestroy() { - if (DEBUG) Slog.v(TAG, "onDestroy()"); - super.onDestroy(); - - if (DEBUG) Slog.v(TAG, "Removing window"); - try { - mWindowManager.removeView(mWindow.getDecorView()); - } catch (Throwable t) { - Slog.w(TAG, "Crashed removing window view", t); - } - } - // end public api - - private void loadSandman() { - mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE)); - } - - private final void attach(IBinder windowToken) { - if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId()); - - if (mSandman == null) { - Slog.w(TAG, "No dream manager found, super.onCreate may not have been called"); - loadSandman(); - } - mWindowToken = windowToken; - mWindow = PolicyManager.makeNewWindow(this); - mWindow.setCallback(this); - mWindow.requestFeature(Window.FEATURE_NO_TITLE); - mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000)); - - if (DEBUG) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s", - windowToken, WindowManager.LayoutParams.TYPE_DREAM)); - - WindowManager.LayoutParams lp = mWindow.getAttributes(); - lp.type = WindowManager.LayoutParams.TYPE_DREAM; - lp.token = windowToken; - lp.windowAnimations = com.android.internal.R.style.Animation_Dream; - lp.flags |= ( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD - | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON - | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0) - ); - mWindow.setAttributes(lp); - - if (DEBUG) Slog.v(TAG, "Created and attached window: " + mWindow); - - mWindow.setWindowManager(null, windowToken, "dream", true); - mWindowManager = mWindow.getWindowManager(); - - // now make it visible (on the ui thread) - mHandler.post(new Runnable(){ - @Override - public void run() { - if (DEBUG) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId()); - try { - applySystemUiVisibilityFlags( - (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0) - | (mFullscreen ? View.SYSTEM_UI_FLAG_FULLSCREEN : 0), - View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN); - getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); - } catch (Throwable t) { - Slog.w("Crashed adding window view", t); - safelyFinish(); - return; - } - - // start it up - try { - onStart(); - } catch (Throwable t) { - Slog.w("Crashed in onStart()", t); - safelyFinish(); - } - }}); - } - - private void safelyFinish() { - if (DEBUG) Slog.v(TAG, "safelyFinish()"); - try { - finish(); - } catch (Throwable t) { - Slog.w(TAG, "Crashed in safelyFinish()", t); - finishInternal(); - return; - } - - if (!mFinished) { - Slog.w(TAG, "Bad dream, did not call super.finish()"); - finishInternal(); - } - } - - private void finishInternal() { - if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished); - if (mFinished) return; - try { - mFinished = true; - - if (mSandman != null) { - mSandman.finishSelf(mWindowToken); - } else { - Slog.w(TAG, "No dream manager found"); - } - stopSelf(); // if launched via any other means - - } catch (Throwable t) { - Slog.w(TAG, "Crashed in finishInternal()", t); - } - } - - private boolean getWindowFlagValue(int flag, boolean defaultValue) { - return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0; - } - - private void applyWindowFlags(int flags, int mask) { - if (mWindow != null) { - WindowManager.LayoutParams lp = mWindow.getAttributes(); - lp.flags = applyFlags(lp.flags, flags, mask); - mWindow.setAttributes(lp); - mWindowManager.updateViewLayout(mWindow.getDecorView(), lp); - } - } - - private boolean getSystemUiVisibilityFlagValue(int flag, boolean defaultValue) { - View v = mWindow == null ? null : mWindow.getDecorView(); - return v == null ? defaultValue : (v.getSystemUiVisibility() & flag) != 0; - } - - private void applySystemUiVisibilityFlags(int flags, int mask) { - View v = mWindow == null ? null : mWindow.getDecorView(); - if (v != null) { - v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask)); - } - } - - private int applyFlags(int oldFlags, int flags, int mask) { - return (oldFlags&~mask) | (flags&mask); - } - - private class DreamServiceWrapper extends IDreamService.Stub { - public void attach(IBinder windowToken) { - Dream.this.attach(windowToken); - } - } - +public class Dream extends DreamService { } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java new file mode 100644 index 0000000000000..f97354fb81b02 --- /dev/null +++ b/core/java/android/service/dreams/DreamService.java @@ -0,0 +1,619 @@ +/** + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.dreams; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.content.Intent; +import android.graphics.drawable.ColorDrawable; +import android.os.Handler; +import android.os.IBinder; +import android.os.ServiceManager; +import android.util.Slog; +import android.view.ActionMode; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.accessibility.AccessibilityEvent; + +import com.android.internal.policy.PolicyManager; + +/** + * Extend this class to implement a custom Dream. + * + *

Dreams are interactive screensavers launched when a charging device is idle, or docked in a + * desk dock. Dreams provide another modality for apps to express themselves, tailored for + * an exhibition/lean-back experience.

+ * + *

Dreams should be declared in the manifest as follows:

+ *
+ * {@code
+ * 
+ *
+ *     
+ *         
+ *         
+ *     
+ *
+ *     
+ *     
+ * 
+ * }
+ * 
+ */ +public class DreamService extends Service implements Window.Callback { + private final static boolean DEBUG = true; + private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; + + /** + * The name of the dream manager service. + * @hide + */ + public static final String DREAM_SERVICE = "dreams"; + + /** + * The {@link Intent} that must be declared as handled by the service. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.service.dreams.DreamService"; + + /** + * Name under which a Dream publishes information about itself. + * This meta-data must reference an XML resource containing + * a <{@link android.R.styleable#Dream dream}> + * tag. + */ + public static final String DREAM_META_DATA = "android.service.dream"; + + private final Handler mHandler = new Handler(); + private IBinder mWindowToken; + private Window mWindow; + private WindowManager mWindowManager; + private IDreamManager mSandman; + private boolean mInteractive = false; + private boolean mLowProfile = true; + private boolean mFullscreen = false; + private boolean mScreenBright = false; + private boolean mFinished; + + // begin Window.Callback methods + /** {@inheritDoc} */ + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK + if (!mInteractive) { + if (DEBUG) Slog.v(TAG, "Finishing on keyEvent"); + safelyFinish(); + return true; + } else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { + if (DEBUG) Slog.v(TAG, "Finishing on back key"); + safelyFinish(); + return true; + } + return mWindow.superDispatchKeyEvent(event); + } + + /** {@inheritDoc} */ + @Override + public boolean dispatchKeyShortcutEvent(KeyEvent event) { + if (!mInteractive) { + if (DEBUG) Slog.v(TAG, "Finishing on keyShortcutEvent"); + safelyFinish(); + return true; + } + return mWindow.superDispatchKeyShortcutEvent(event); + } + + /** {@inheritDoc} */ + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + // TODO: create more flexible version of mInteractive that allows clicks + // but finish()es on any other kind of activity + if (!mInteractive) { + if (DEBUG) Slog.v(TAG, "Finishing on touchEvent"); + safelyFinish(); + return true; + } + return mWindow.superDispatchTouchEvent(event); + } + + /** {@inheritDoc} */ + @Override + public boolean dispatchTrackballEvent(MotionEvent event) { + if (!mInteractive) { + if (DEBUG) Slog.v(TAG, "Finishing on trackballEvent"); + safelyFinish(); + return true; + } + return mWindow.superDispatchTrackballEvent(event); + } + + /** {@inheritDoc} */ + @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) { + if (!mInteractive) { + if (DEBUG) Slog.v(TAG, "Finishing on genericMotionEvent"); + safelyFinish(); + return true; + } + return mWindow.superDispatchGenericMotionEvent(event); + } + + /** {@inheritDoc} */ + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return false; + } + + /** {@inheritDoc} */ + @Override + public View onCreatePanelView(int featureId) { + return null; + } + + /** {@inheritDoc} */ + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + return false; + } + + /** {@inheritDoc} */ + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + return false; + } + + /** {@inheritDoc} */ + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + return false; + } + + /** {@inheritDoc} */ + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + return false; + } + + /** {@inheritDoc} */ + @Override + public void onWindowAttributesChanged(LayoutParams attrs) { + } + + /** {@inheritDoc} */ + @Override + public void onContentChanged() { + } + + /** {@inheritDoc} */ + @Override + public void onWindowFocusChanged(boolean hasFocus) { + } + + /** {@inheritDoc} */ + @Override + public void onAttachedToWindow() { + } + + /** {@inheritDoc} */ + @Override + public void onDetachedFromWindow() { + } + + /** {@inheritDoc} */ + @Override + public void onPanelClosed(int featureId, Menu menu) { + } + + /** {@inheritDoc} */ + @Override + public boolean onSearchRequested() { + return false; + } + + /** {@inheritDoc} */ + @Override + public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) { + return null; + } + + /** {@inheritDoc} */ + @Override + public void onActionModeStarted(ActionMode mode) { + } + + /** {@inheritDoc} */ + @Override + public void onActionModeFinished(ActionMode mode) { + } + // end Window.Callback methods + + // begin public api + /** + * Retrieves the current {@link android.view.WindowManager} for the dream. + * Behaves similarly to {@link android.app.Activity#getWindowManager()}. + * + * @return The current window manager, or null if the dream is not started. + */ + public WindowManager getWindowManager() { + return mWindowManager; + } + + /** + * Retrieves the current {@link android.view.Window} for the dream. + * Behaves similarly to {@link android.app.Activity#getWindow()}. + * + * @return The current window, or null if the dream is not started. + */ + public Window getWindow() { + return mWindow; + } + + /** + * Inflates a layout resource and set it to be the content view for this Dream. + * Behaves similarly to {@link android.app.Activity#setContentView(int)}. + * + *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

+ * + * @param layoutResID Resource ID to be inflated. + * + * @see #setContentView(android.view.View) + * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) + */ + public void setContentView(int layoutResID) { + getWindow().setContentView(layoutResID); + } + + /** + * Sets a view to be the content view for this Dream. + * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)}, + * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view. + * + *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

+ * @param view The desired content to display. + * + * @see #setContentView(int) + * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) + */ + public void setContentView(View view) { + getWindow().setContentView(view); + } + + /** + * Sets a view to be the content view for this Dream. + * Behaves similarly to + * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}. + * + *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

+ * + * @param view The desired content to display. + * @param params Layout parameters for the view. + * + * @see #setContentView(android.view.View) + * @see #setContentView(int) + */ + public void setContentView(View view, ViewGroup.LayoutParams params) { + getWindow().setContentView(view, params); + } + + /** + * Adds a view to the Dream's window, leaving other content views in place. + * + *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

+ * + * @param view The desired content to display. + * @param params Layout parameters for the view. + */ + public void addContentView(View view, ViewGroup.LayoutParams params) { + getWindow().addContentView(view, params); + } + + /** + * Finds a view that was identified by the id attribute from the XML that + * was processed in {@link #onCreate}. + * + *

Note: Requires a window, do not call before {@link #onAttachedToWindow()}

+ * + * @return The view if found or null otherwise. + */ + public View findViewById(int id) { + return getWindow().findViewById(id); + } + + /** + * Marks this dream as interactive to receive input events. + * + *

Non-interactive dreams (default) will dismiss on the first input event.

+ * + *

Interactive dreams should call {@link #finish()} to dismiss themselves.

+ * + * @param interactive True if this dream will handle input events. + */ + public void setInteractive(boolean interactive) { + mInteractive = interactive; + } + + /** + * Returns whether or not this dream is interactive. Defaults to false. + * + * @see #setInteractive(boolean) + */ + public boolean isInteractive() { + return mInteractive; + } + + /** + * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. + * + * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE + */ + public void setLowProfile(boolean lowProfile) { + mLowProfile = lowProfile; + int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE; + applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag); + } + + /** + * Returns whether or not this dream is in low profile mode. Defaults to true. + * + * @see #setLowProfile(boolean) + */ + public boolean isLowProfile() { + return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile); + } + + /** + * Sets View.SYSTEM_UI_FLAG_FULLSCREEN on the content view. + * + * @param fullscreen True to set View.SYSTEM_UI_FLAG_FULLSCREEN + */ + public void setFullscreen(boolean fullscreen) { + mFullscreen = fullscreen; + int flag = View.SYSTEM_UI_FLAG_FULLSCREEN; + applySystemUiVisibilityFlags(mFullscreen ? flag : 0, flag); + } + + /** + * Returns whether or not this dream is in fullscreen mode. Defaults to false. + * + * @see #setFullscreen(boolean) + */ + public boolean isFullscreen() { + return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_FULLSCREEN, mFullscreen); + } + + /** + * Marks this dream as keeping the screen bright while dreaming. + * + * @param screenBright True to keep the screen bright while dreaming. + */ + public void setScreenBright(boolean screenBright) { + mScreenBright = screenBright; + int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; + applyWindowFlags(mScreenBright ? flag : 0, flag); + } + + /** + * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false, + * allowing the screen to dim if necessary. + * + * @see #setScreenBright(boolean) + */ + public boolean isScreenBright() { + return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright); + } + + /** + * Called when this Dream is constructed. Place your initialization here. + * + *

Subclasses must call through to the superclass implementation.

+ */ + @Override + public void onCreate() { + if (DEBUG) Slog.v(TAG, "onCreate() on thread " + Thread.currentThread().getId()); + super.onCreate(); + loadSandman(); + } + + /** + * Called when this Dream is started. The window is created and visible at this point. + */ + public void onStart() { + if (DEBUG) Slog.v(TAG, "onStart()"); + // hook for subclasses + } + + /** {@inheritDoc} */ + @Override + public final IBinder onBind(Intent intent) { + if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); + return new DreamServiceWrapper(); + } + + /** + * Stops the dream, detaches from the window, and wakes up. + * + *

Subclasses must call through to the superclass implementation.

+ * + *

After this method is called, the service will be stopped.

+ */ + public void finish() { + if (DEBUG) Slog.v(TAG, "finish()"); + finishInternal(); + } + + /** {@inheritDoc} */ + @Override + public void onDestroy() { + if (DEBUG) Slog.v(TAG, "onDestroy()"); + super.onDestroy(); + + if (DEBUG) Slog.v(TAG, "Removing window"); + try { + mWindowManager.removeView(mWindow.getDecorView()); + } catch (Throwable t) { + Slog.w(TAG, "Crashed removing window view", t); + } + } + // end public api + + private void loadSandman() { + mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE)); + } + + private final void attach(IBinder windowToken) { + if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId()); + + if (mSandman == null) { + Slog.w(TAG, "No dream manager found, super.onCreate may not have been called"); + loadSandman(); + } + mWindowToken = windowToken; + mWindow = PolicyManager.makeNewWindow(this); + mWindow.setCallback(this); + mWindow.requestFeature(Window.FEATURE_NO_TITLE); + mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000)); + + if (DEBUG) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s", + windowToken, WindowManager.LayoutParams.TYPE_DREAM)); + + WindowManager.LayoutParams lp = mWindow.getAttributes(); + lp.type = WindowManager.LayoutParams.TYPE_DREAM; + lp.token = windowToken; + lp.windowAnimations = com.android.internal.R.style.Animation_Dream; + lp.flags |= ( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0) + ); + mWindow.setAttributes(lp); + + if (DEBUG) Slog.v(TAG, "Created and attached window: " + mWindow); + + mWindow.setWindowManager(null, windowToken, "dream", true); + mWindowManager = mWindow.getWindowManager(); + + // now make it visible (on the ui thread) + mHandler.post(new Runnable(){ + @Override + public void run() { + if (DEBUG) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId()); + try { + applySystemUiVisibilityFlags( + (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0) + | (mFullscreen ? View.SYSTEM_UI_FLAG_FULLSCREEN : 0), + View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN); + getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); + } catch (Throwable t) { + Slog.w("Crashed adding window view", t); + safelyFinish(); + return; + } + + // start it up + try { + onStart(); + } catch (Throwable t) { + Slog.w("Crashed in onStart()", t); + safelyFinish(); + } + }}); + } + + private void safelyFinish() { + if (DEBUG) Slog.v(TAG, "safelyFinish()"); + try { + finish(); + } catch (Throwable t) { + Slog.w(TAG, "Crashed in safelyFinish()", t); + finishInternal(); + return; + } + + if (!mFinished) { + Slog.w(TAG, "Bad dream, did not call super.finish()"); + finishInternal(); + } + } + + private void finishInternal() { + if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished); + if (mFinished) return; + try { + mFinished = true; + + if (mSandman != null) { + mSandman.finishSelf(mWindowToken); + } else { + Slog.w(TAG, "No dream manager found"); + } + stopSelf(); // if launched via any other means + + } catch (Throwable t) { + Slog.w(TAG, "Crashed in finishInternal()", t); + } + } + + private boolean getWindowFlagValue(int flag, boolean defaultValue) { + return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0; + } + + private void applyWindowFlags(int flags, int mask) { + if (mWindow != null) { + WindowManager.LayoutParams lp = mWindow.getAttributes(); + lp.flags = applyFlags(lp.flags, flags, mask); + mWindow.setAttributes(lp); + mWindowManager.updateViewLayout(mWindow.getDecorView(), lp); + } + } + + private boolean getSystemUiVisibilityFlagValue(int flag, boolean defaultValue) { + View v = mWindow == null ? null : mWindow.getDecorView(); + return v == null ? defaultValue : (v.getSystemUiVisibility() & flag) != 0; + } + + private void applySystemUiVisibilityFlags(int flags, int mask) { + View v = mWindow == null ? null : mWindow.getDecorView(); + if (v != null) { + v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask)); + } + } + + private int applyFlags(int oldFlags, int flags, int mask) { + return (oldFlags&~mask) | (flags&mask); + } + + private class DreamServiceWrapper extends IDreamService.Stub { + public void attach(IBinder windowToken) { + DreamService.this.attach(windowToken); + } + } + +} diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9759bdcb0f7c9..76986241ab1c5 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5307,9 +5307,9 @@ diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index eb8a5ffe4a66d..3b40fba01a25b 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -198,9 +198,8 @@ android:enabled="false" > - + - diff --git a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java index 6b5c9c06405c7..3bb808f5e994d 100644 --- a/packages/SystemUI/src/com/android/systemui/BeanBagDream.java +++ b/packages/SystemUI/src/com/android/systemui/BeanBagDream.java @@ -1,10 +1,10 @@ package com.android.systemui; -import android.service.dreams.Dream; +import android.service.dreams.DreamService; import com.android.systemui.BeanBag.Board; -public class BeanBagDream extends Dream { +public class BeanBagDream extends DreamService { private Board mBoard; diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java index 8e3ce3be54775..011bf9ca4819e 100644 --- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java +++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java @@ -22,7 +22,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; -import android.service.dreams.Dream; +import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.util.Slog; @@ -69,7 +69,7 @@ public class Somnambulator extends Activity { Slog.i(TAG, "Dreams currently disabled for docks."); } else { IDreamManager somnambulist = IDreamManager.Stub.asInterface( - ServiceManager.checkService(Dream.DREAM_SERVICE)); + ServiceManager.checkService(DreamService.DREAM_SERVICE)); if (somnambulist != null) { try { Slog.v(TAG, "Dreaming on " + (docked ? "dock insertion" : "user request")); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index e084368ca5e07..3fea0a01469f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -46,7 +46,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; -import android.service.dreams.Dream; +import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.util.DisplayMetrics; import android.util.Log; @@ -265,7 +265,7 @@ public class PhoneStatusBar extends BaseStatusBar { .getDefaultDisplay(); mDreamManager = IDreamManager.Stub.asInterface( - ServiceManager.checkService(Dream.DREAM_SERVICE)); + ServiceManager.checkService(DreamService.DREAM_SERVICE)); super.start(); // calls createAndAddWindows() diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 738e19b1f2678..b684c90d05dac 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -38,7 +38,7 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.server.search.SearchManagerService; -import android.service.dreams.Dream; +import android.service.dreams.DreamService; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -741,7 +741,7 @@ class ServerThread extends Thread { Slog.i(TAG, "Dreams Service"); // Dreams (interactive idle-time views, a/k/a screen savers) dreamy = new DreamManagerService(context, wmHandler); - ServiceManager.addService(Dream.DREAM_SERVICE, dreamy); + ServiceManager.addService(DreamService.DREAM_SERVICE, dreamy); } catch (Throwable e) { reportWtf("starting DreamManagerService", e); } diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index 3b8caba6635bd..d1af2b0229ef7 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -39,7 +39,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; -import android.service.dreams.Dream; +import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.util.Slog; @@ -501,7 +501,7 @@ class UiModeManagerService extends IUiModeManager.Stub { Slog.i(TAG, "Activating dream while docked."); try { IDreamManager dreamManagerService = IDreamManager.Stub.asInterface( - ServiceManager.getService(Dream.DREAM_SERVICE)); + ServiceManager.getService(DreamService.DREAM_SERVICE)); dreamManagerService.dream(); } catch (RemoteException ex) { Slog.e(TAG, "Could not start dream when docked.", ex); diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/java/com/android/server/dreams/DreamController.java index c01a45dcb5d5b..6db495a5964a7 100644 --- a/services/java/com/android/server/dreams/DreamController.java +++ b/services/java/com/android/server/dreams/DreamController.java @@ -25,7 +25,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.IBinder.DeathRecipient; -import android.service.dreams.Dream; +import android.service.dreams.DreamService; import android.service.dreams.IDreamService; import android.util.Slog; import android.view.IWindowManager; @@ -48,9 +48,9 @@ final class DreamController { private final Listener mListener; private final IWindowManager mIWindowManager; - private final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED) + private final Intent mDreamingStartedIntent = new Intent(Intent.ACTION_DREAMING_STARTED) .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - private final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED) + private final Intent mDreamingStoppedIntent = new Intent(Intent.ACTION_DREAMING_STOPPED) .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); private final Intent mCloseNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -98,8 +98,7 @@ final class DreamController { return; } - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Dream.CATEGORY_DREAM); + Intent intent = new Intent(DreamService.SERVICE_INTERFACE); intent.setComponent(name); intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); try { diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index ad138e80140b7..9052e0e553655 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -51,7 +51,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; -import android.service.dreams.Dream; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -363,8 +362,8 @@ public final class PowerManagerService extends IPowerManager.Stub mContext.registerReceiver(new BootCompletedReceiver(), filter, null, mHandler); filter = new IntentFilter(); - filter.addAction(Dream.ACTION_DREAMING_STARTED); - filter.addAction(Dream.ACTION_DREAMING_STOPPED); + filter.addAction(Intent.ACTION_DREAMING_STARTED); + filter.addAction(Intent.ACTION_DREAMING_STOPPED); mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler); filter = new IntentFilter();