diff options
-rw-r--r-- | api/current.txt | 10 | ||||
-rw-r--r-- | core/java/android/service/dreams/Dream.java | 286 |
2 files changed, 230 insertions, 66 deletions
diff --git a/api/current.txt b/api/current.txt index 2381732..b7616f1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -20270,8 +20270,11 @@ package android.service.dreams { method public void finish(); method public android.view.Window getWindow(); method public android.view.WindowManager getWindowManager(); + method public boolean isFullscreen(); method public boolean isInteractive(); - method protected void lightsOut(); + method public boolean isLowProfile(); + method public boolean isScreenBright(); + method protected deprecated void lightsOut(); method public void onActionModeFinished(android.view.ActionMode); method public void onActionModeStarted(android.view.ActionMode); method public void onAttachedToWindow(); @@ -20292,11 +20295,14 @@ package android.service.dreams { method public void setContentView(int); method public void setContentView(android.view.View); method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); + method public void setFullscreen(boolean); 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 METADATA_NAME_CONFIG_ACTIVITY = "android.service.dreams.config_activity"; - field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.Dream"; } } diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java index 4a23d39..bd220a1 100644 --- a/core/java/android/service/dreams/Dream.java +++ b/core/java/android/service/dreams/Dream.java @@ -44,22 +44,47 @@ import com.android.internal.policy.PolicyManager; * <p>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.</p> + * + * <p>Dreams should be declared in the manifest as follows:</p> + * <pre> + * {@code + * <service + * android:name=".MyDream" + * android:exported="true" + * android:icon="@drawable/my_icon" + * android:label="@string/my_dream_label" > + * + * <intent-filter> + * <action android:name="android.intent.action.MAIN" /> + * <category android:name="android.intent.category.DREAM" /> + * </intent-filter> + * + * <!-- Point to configuration activity for this dream (optional) --> + * <meta-data + * android:name="android.service.dreams.config_activity" + * android:value="com.example.mypackage/com.example.mypackage.MyDreamSettingsActivity" /> + * </service> + * } + * </pre> */ public class Dream extends Service implements Window.Callback { private final static boolean DEBUG = true; private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; /** - * The {@link Intent} that must be declared as handled by the service. - * To be supported, the service must also require the - * {@link android.Manifest.permission#BIND_WALLPAPER} permission so - * that other applications can not abuse it. + * Used with {@link #ACTION_MAIN} to declare the necessary intent-filter for a dream. + * + * @see Dream */ - @SdkConstant(SdkConstantType.SERVICE_ACTION) - public static final String SERVICE_INTERFACE = - "android.service.dreams.Dream"; + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_DREAM = + "android.intent.category.DREAM"; - /** Service meta-data key for declaring an optional configuration activity. */ + /** + * Service meta-data key for declaring an optional configuration activity. + * + * @see Dream + * */ public static final String METADATA_NAME_CONFIG_ACTIVITY = "android.service.dreams.config_activity"; @@ -86,10 +111,14 @@ public class Dream extends Service implements Window.Callback { private Window mWindow; private WindowManager mWindowManager; private IDreamManager mSandman; - private boolean mInteractive; + 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 @@ -105,6 +134,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchKeyEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) { if (!mInteractive) { @@ -115,6 +145,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchKeyShortcutEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchTouchEvent(MotionEvent event) { // TODO: create more flexible version of mInteractive that allows clicks @@ -127,6 +158,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchTouchEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchTrackballEvent(MotionEvent event) { if (!mInteractive) { @@ -137,6 +169,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchTrackballEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { if (!mInteractive) { @@ -147,86 +180,112 @@ public class Dream extends Service implements Window.Callback { 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; } @@ -235,6 +294,8 @@ public class Dream extends Service implements Window.Callback { * Inflates a layout resource and set it to be the content view for this Dream. * Behaves similarly to {@link android.app.Activity#setContentView(int)}. * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * * @param layoutResID Resource ID to be inflated. * * @see #setContentView(android.view.View) @@ -248,7 +309,8 @@ public class Dream extends Service implements Window.Callback { * 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. - * + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> * @param view The desired content to display. * * @see #setContentView(int) @@ -263,6 +325,8 @@ public class Dream extends Service implements Window.Callback { * Behaves similarly to * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}. * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * * @param view The desired content to display. * @param params Layout parameters for the view. * @@ -275,7 +339,9 @@ public class Dream extends Service implements Window.Callback { /** * Adds a view to the Dream's window, leaving other content views in place. - * + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * * @param view The desired content to display. * @param params Layout parameters for the view. */ @@ -284,6 +350,25 @@ public class Dream extends Service implements Window.Callback { } /** + * Finds a view that was identified by the id attribute from the XML that + * was processed in {@link #onCreate}. + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * + * @return The view if found or null otherwise. + */ + public View findViewById(int id) { + return getWindow().findViewById(id); + } + + /** FIXME remove once platform dreams are updated */ + @Deprecated + protected void lightsOut() { + setLowProfile(true); + setFullscreen(true); + } + + /** * Marks this dream as interactive to receive input events. * * <p>Non-interactive dreams (default) will dismiss on the first input event.</p> @@ -297,36 +382,79 @@ public class Dream extends Service implements Window.Callback { } /** - * Returns whether or not this dream is interactive. + * Returns whether or not this dream is interactive. Defaults to false. + * + * @see #setInteractive(boolean) */ public boolean isInteractive() { return mInteractive; } - /** Convenience method for setting View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. */ - protected void lightsOut() { - // turn the lights down low - final View v = mWindow.getDecorView(); - if (v != null) { - v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE - | View.SYSTEM_UI_FLAG_FULLSCREEN); - } + /** + * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. + * + * @param lightsOut 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); } /** - * Finds a view that was identified by the id attribute from the XML that - * was processed in {@link #onCreate}. + * Returns whether or not this dream is in low profile mode. Defaults to true. * - * @return The view if found or null otherwise. + * @see #setLowProfile(boolean) */ - public View findViewById(int id) { - return getWindow().findViewById(id); + 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. + * <p>Subclasses must call through to the superclass implementation.</p> */ @Override public void onCreate() { @@ -336,23 +464,51 @@ public class Dream extends Service implements Window.Callback { } /** - * Called when this Dream is started. + * 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 - Slog.v(TAG, "called Dream.onStart()"); } - private void loadSandman() { - mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); + /** {@inheritDoc} */ + @Override + public final IBinder onBind(Intent intent) { + if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); + return new DreamServiceWrapper(); } /** - * Creates a new dream window, attaches the current content view, and shows it. - * - * @param windowToken Binder to attach to the window to allow access to the correct window type. - * @hide + * Stops the dream, detaches from the window, and wakes up. + * + * <p>Subclasses must call through to the superclass implementation.</p> + * + * <p>After this method is called, the service will be stopped.</p> */ + 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("dreams")); + } + private final void attach(IBinder windowToken) { if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId()); @@ -375,7 +531,8 @@ public class Dream extends Service implements Window.Callback { 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 + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0) ); mWindow.setAttributes(lp); @@ -389,8 +546,11 @@ public class Dream extends Service implements Window.Callback { @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); @@ -424,18 +584,6 @@ public class Dream extends Service implements Window.Callback { } } - /** - * Stops the dream, detaches from the window, and wakes up. - * - * Subclasses must call through to the superclass implementation. - * - * <p>After this method is called, the service will be stopped.</p> - */ - public void finish() { - if (DEBUG) Slog.v(TAG, "finish()"); - finishInternal(); - } - private void finishInternal() { if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished); if (mFinished) return; @@ -454,23 +602,33 @@ public class Dream extends Service implements Window.Callback { } } - @Override - public void onDestroy() { - if (DEBUG) Slog.v(TAG, "onDestroy()"); - super.onDestroy(); + private boolean getWindowFlagValue(int flag, boolean defaultValue) { + return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0; + } - if (DEBUG) Slog.v(TAG, "Removing window"); - try { - mWindowManager.removeView(mWindow.getDecorView()); - } catch (Throwable t) { - Slog.w(TAG, "Crashed removing window view", t); + 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); } } - @Override - public final IBinder onBind(Intent intent) { - if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); - return new DreamServiceWrapper(); + 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 { |