diff options
author | Daniel Sandler <dsandler@android.com> | 2012-04-10 05:33:07 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-04-10 05:33:07 -0700 |
commit | c38cf4c7dbe7d96255d42dabf8ca801830813f5e (patch) | |
tree | c34bc1561f67c0838d7ebd4d625b568738dc4589 | |
parent | 06cce885296f60b6cc2d0dad3d167681536a53a5 (diff) | |
parent | 7d276c377ce0c56630c06a6da431a6cb9bd76d1e (diff) | |
download | frameworks_base-c38cf4c7dbe7d96255d42dabf8ca801830813f5e.zip frameworks_base-c38cf4c7dbe7d96255d42dabf8ca801830813f5e.tar.gz frameworks_base-c38cf4c7dbe7d96255d42dabf8ca801830813f5e.tar.bz2 |
Merge "New Android Dreams architecture, disabled for now."
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | core/java/android/service/dreams/Dream.java | 392 | ||||
-rw-r--r-- | core/java/android/service/dreams/DreamManagerService.java | 182 | ||||
-rw-r--r-- | core/java/android/service/dreams/IDreamManager.aidl | 30 | ||||
-rw-r--r-- | core/java/android/service/dreams/IDreamService.aidl | 24 | ||||
-rw-r--r-- | core/java/android/view/WindowManager.java | 6 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 25 | ||||
-rw-r--r-- | core/res/res/anim/slow_fade_in.xml | 24 | ||||
-rwxr-xr-x | core/res/res/values/config.xml | 2 | ||||
-rw-r--r-- | core/res/res/values/public.xml | 4 | ||||
-rw-r--r-- | core/res/res/values/styles.xml | 6 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 149 | ||||
-rw-r--r-- | services/java/com/android/server/PowerManagerService.java | 15 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 20 | ||||
-rw-r--r-- | services/java/com/android/server/wm/WindowManagerService.java | 12 |
15 files changed, 808 insertions, 85 deletions
@@ -132,6 +132,8 @@ LOCAL_SRC_FILES += \ core/java/android/os/IRemoteCallback.aidl \ core/java/android/os/IUpdateLock.aidl \ core/java/android/os/IVibratorService.aidl \ + core/java/android/service/dreams/IDreamManager.aidl \ + core/java/android/service/dreams/IDreamService.aidl \ core/java/android/service/wallpaper/IWallpaperConnection.aidl \ core/java/android/service/wallpaper/IWallpaperEngine.aidl \ core/java/android/service/wallpaper/IWallpaperService.aidl \ diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java new file mode 100644 index 0000000..83464c9 --- /dev/null +++ b/core/java/android/service/dreams/Dream.java @@ -0,0 +1,392 @@ +/** + * + */ +package android.service.dreams; + +import com.android.internal.policy.PolicyManager; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.graphics.drawable.ColorDrawable; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; +import android.view.ActionMode; +import android.view.IWindowManager; +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.LayoutParams; +import android.view.accessibility.AccessibilityEvent; +import android.view.WindowManager; +import android.view.WindowManagerImpl; + +/** + * @hide + * + */ +public class Dream extends Service implements Window.Callback { + private final static boolean DEBUG = true; + private final static String TAG = "Dream"; + + /** + * 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. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.service.dreams.Dream"; + + private Window mWindow; + + private WindowManager mWindowManager; + private IDreamManager mSandman; + + private boolean mInteractive; + + final Handler mHandler = new Handler(); + + boolean mFinished = false; + + // begin Window.Callback methods + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchKeyEvent(event); + } + + @Override + public boolean dispatchKeyShortcutEvent(KeyEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchKeyShortcutEvent(event); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchTouchEvent(event); + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchTrackballEvent(event); + } + + @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchGenericMotionEvent(event); + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return false; + } + + @Override + public View onCreatePanelView(int featureId) { + return null; + } + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + return false; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + return false; + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + return false; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + return false; + } + + @Override + public void onWindowAttributesChanged(LayoutParams attrs) { + + } + + @Override + public void onContentChanged() { + + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + + } + + @Override + public void onAttachedToWindow() { + mWindow.addFlags( + WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + ); + lightsOut(); + } + + @Override + public void onDetachedFromWindow() { + } + + @Override + public void onPanelClosed(int featureId, Menu menu) { + } + + @Override + public boolean onSearchRequested() { + return false; + } + + @Override + public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) { + return null; + } + + @Override + public void onActionModeStarted(ActionMode mode) { + } + + @Override + public void onActionModeFinished(ActionMode mode) { + } + // end Window.Callback methods + + public WindowManager getWindowManager() { + return mWindowManager; + } + + public Window getWindow() { + return mWindow; + } + + /** + * Called when this Dream is constructed. Place your initialization here. + * + * Subclasses must call through to the superclass implementation. + */ + @Override + public void onCreate() { + super.onCreate(); + + if (DEBUG) Slog.v(TAG, "Dream created on thread " + Thread.currentThread().getId()); + + mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); + } + + /** + * Called when this Dream is started. Place your initialization here. + * + * Subclasses must call through to the superclass implementation. + * + * XXX(dsandler) Might want to make this final and have a different method for clients to override + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + + /** + * Inflate a layout resource and set it to be the content view for this Dream. + * Behaves similarly to {@link android.app.Activity#setContentView(int)}. + * + * @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); + } + + /** + * Set 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. + * + * @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); + } + + /** + * Set 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)}. + * + * @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); + } + + /** + * Add a view to the Dream's window, leaving other content views in place. + * + * @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); + } + + /** + * @param mInteractive the mInteractive to set + */ + public void setInteractive(boolean mInteractive) { + this.mInteractive = mInteractive; + } + + /** + * @return the mInteractive + */ + 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); + } + } + + /** + * Finds a view that was identified by the id attribute from the XML that + * was processed in {@link #onCreate}. + * + * @return The view if found or null otherwise. + */ + public View findViewById(int id) { + return getWindow().findViewById(id); + } + + /** + * Called when this Dream is being removed from the screen and stopped. + */ + @Override + public void onDestroy() { + super.onDestroy(); + mWindowManager.removeView(mWindow.getDecorView()); + } + + /** + * 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 + */ + final /*package*/ void attach(IBinder windowToken) { + if (DEBUG) Slog.v(TAG, "Dream attached on thread " + Thread.currentThread().getId()); + + mWindow = PolicyManager.makeNewWindow(this); + mWindow.setCallback(this); + mWindow.requestFeature(Window.FEATURE_NO_TITLE); + mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000)); + + if (DEBUG) Slog.v(TAG, "attaching window token: " + windowToken + + " to window of type " + 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; + + //WindowManagerImpl.getDefault().addView(mWindow.getDecorView(), lp); + + if (DEBUG) Slog.v(TAG, "created and attached window: " + mWindow); + + mWindow.setWindowManager(null, windowToken, "dream", true); + mWindowManager = mWindow.getWindowManager(); + + // now make it visible + mHandler.post(new Runnable(){ + @Override + public void run() { + if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId()); + + getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); + }}); + } + + /** + * Stop the dream and wake up. + * + * After this method is called, the service will be stopped. + */ + public void finish() { + if (mFinished) return; + try { + mSandman.awaken(); // assuming we were started by the DreamManager + stopSelf(); // if launched via any other means + mFinished = true; + } catch (RemoteException ex) { + // sigh + } + } + + class IDreamServiceWrapper extends IDreamService.Stub { + public IDreamServiceWrapper() { + } + + public void attach(IBinder windowToken) { + Dream.this.attach(windowToken); + } + } + + /** + * Implement to return the implementation of the internal accessibility + * service interface. Subclasses should not override. + */ + @Override + public final IBinder onBind(Intent intent) { + return new IDreamServiceWrapper(); + } +} diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java new file mode 100644 index 0000000..8712fa2 --- /dev/null +++ b/core/java/android/service/dreams/DreamManagerService.java @@ -0,0 +1,182 @@ +package android.service.dreams; + +import static android.provider.Settings.Secure.SCREENSAVER_COMPONENT; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +import com.android.internal.view.IInputMethod; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.provider.Settings; +import android.util.Log; +import android.util.Slog; +import android.view.IWindowManager; +import android.view.WindowManager; + +/** + * + * @hide + * + */ + +public class DreamManagerService + extends IDreamManager.Stub + implements ServiceConnection +{ + private static final boolean DEBUG = true; + private static final String TAG = "DreamManagerService"; + + final Object mLock = new Object[0]; + + private Context mContext; + private IWindowManager mIWindowManager; + + private ComponentName mCurrentDreamComponent; + private IDreamService mCurrentDream; + private Binder mCurrentDreamToken; + + public DreamManagerService(Context context) { + if (DEBUG) Slog.v(TAG, "DreamManagerService startup"); + mContext = context; + mIWindowManager = IWindowManager.Stub.asInterface( + ServiceManager.getService(Context.WINDOW_SERVICE)); + } + + private void checkPermission(String permission) { + if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) { + throw new SecurityException("Access denied to process: " + Binder.getCallingPid() + + ", must have permission " + permission); + } + } + + // IDreamManager method + public void dream() { + ComponentName name = getDreamComponent(); + if (name != null) { + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + bindDreamComponentL(name, false); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + } + + // IDreamManager method + public void setDreamComponent(ComponentName name) { + Settings.Secure.putString(mContext.getContentResolver(), SCREENSAVER_COMPONENT, name.flattenToString()); + } + + // IDreamManager method + public ComponentName getDreamComponent() { + // TODO(dsandler) don't load this every time, watch the value + String component = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENT); + if (component == null) { + component = mContext.getResources().getString( + com.android.internal.R.string.config_defaultDreamComponent); + } + if (component != null) { + return ComponentName.unflattenFromString(component); + } else { + return null; + } + } + + // IDreamManager method + public void testDream(ComponentName name) { + if (DEBUG) Slog.v(TAG, "startDream name=" + name + + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); +// checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + bindDreamComponentL(name, true); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + // IDreamManager method + public void awaken() { + if (DEBUG) Slog.v(TAG, "awaken()"); + synchronized (mLock) { + if (mCurrentDream != null) { + mContext.unbindService(this); + } + } + } + + public void bindDreamComponentL(ComponentName componentName, boolean test) { + if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName + + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + + Intent intent = new Intent(Intent.ACTION_MAIN) + .setComponent(componentName) + .addFlags( + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + ) + .putExtra("android.dreams.TEST", test); + + if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) { + Slog.w(TAG, "unable to bind service: " + componentName); + return; + } + mCurrentDreamComponent = componentName; + mCurrentDreamToken = new Binder(); + try { + if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken + + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM); + mIWindowManager.addWindowToken(mCurrentDreamToken, + WindowManager.LayoutParams.TYPE_DREAM); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to add window token. Proceed at your own risk."); + } + + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) Slog.v(TAG, "connected to dream: " + name + " binder=" + service + " thread=" + Thread.currentThread().getId()); + + mCurrentDream = IDreamService.Stub.asInterface(service); + try { + if (DEBUG) Slog.v(TAG, "attaching with token:" + mCurrentDreamToken); + mCurrentDream.attach(mCurrentDreamToken); + } catch (RemoteException ex) { + Slog.w(TAG, "Unable to send window token to dream:" + ex); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream); + mCurrentDream = null; + mCurrentDreamToken = null; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Dreamland:"); + pw.print(" component="); pw.println(mCurrentDreamComponent); + pw.print(" token="); pw.println(mCurrentDreamToken); + pw.print(" dream="); pw.println(mCurrentDream); + } + + public void systemReady() { + if (DEBUG) Slog.v(TAG, "ready to dream!"); + } + +} diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl new file mode 100644 index 0000000..7225013 --- /dev/null +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -0,0 +1,30 @@ +/** + * 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.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.content.ComponentName; + +/** @hide */ +interface IDreamManager { + void dream(); + void awaken(); + void setDreamComponent(in ComponentName componentName); + ComponentName getDreamComponent(); + void testDream(in ComponentName componentName); +}
\ No newline at end of file diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl new file mode 100644 index 0000000..1bb241a --- /dev/null +++ b/core/java/android/service/dreams/IDreamService.aidl @@ -0,0 +1,24 @@ +/* + * 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; + +/** + * @hide + */ +oneway interface IDreamService { + void attach(IBinder windowToken); +} diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index f3ef329..bc310b0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -423,6 +423,12 @@ public interface WindowManager extends ViewManager { public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22; /** + * Window type: Dreams (screen saver) window, just above keyguard. + * @hide + */ + public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23; + + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 491cd67..66bdc5d 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1049,6 +1049,31 @@ public interface WindowManagerPolicy { public void lockNow(); /** + * Check to see if a screensaver should be run instead of powering off the screen on timeout. + * + * @return true if the screensaver should run, false if the screen should turn off. + * + * @hide + */ + public boolean isScreenSaverEnabled(); + + /** + * Start the screensaver (if it is enabled and not yet running). + * + * @return Whether the screensaver was successfully started. + * + * @hide + */ + public boolean startScreenSaver(); + + /** + * Stop the screensaver if it is running. + * + * @hide + */ + public void stopScreenSaver(); + + /** * Print the WindowManagerPolicy's state into the given stream. * * @param prefix Text to print at the front of each line. diff --git a/core/res/res/anim/slow_fade_in.xml b/core/res/res/anim/slow_fade_in.xml new file mode 100644 index 0000000..21a2c78 --- /dev/null +++ b/core/res/res/anim/slow_fade_in.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/res/anim/fade_in.xml +** +** Copyright 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. +*/ +--> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@interpolator/decelerate_quad" + android:fromAlpha="0.0" android:toAlpha="1.0" + android:duration="1000" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 4fde018..e80e30a 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -837,6 +837,8 @@ <!-- Name of the wimax state tracker clas --> <string name="config_wimaxStateTrackerClassname" translatable="false"></string> + <!-- enable screen saver feature --> + <bool name="config_enableDreams">false</bool> <!-- Name of screensaver components to look for if none has been chosen by the user --> <string name="config_defaultDreamComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index ca0e913..cbfc1a4 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1110,6 +1110,7 @@ <java-symbol type="style" name="Animation.PopupWindow" /> <java-symbol type="style" name="Animation.TypingFilter" /> <java-symbol type="style" name="Animation.TypingFilterRestore" /> + <java-symbol type="style" name="Animation.Dream" /> <java-symbol type="style" name="Theme.DeviceDefault.Dialog.Alert" /> <java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" /> <java-symbol type="style" name="Theme.Dialog.Alert" /> @@ -1262,7 +1263,6 @@ <java-symbol type="layout" name="screen_title_icons" /> <java-symbol type="string" name="abbrev_wday_month_day_no_year" /> <java-symbol type="string" name="android_upgrading_title" /> - <java-symbol type="string" name="config_defaultDreamComponent" /> <java-symbol type="string" name="faceunlock_multiple_failures" /> <java-symbol type="string" name="global_action_power_off" /> <java-symbol type="string" name="global_actions_airplane_mode_off_status" /> @@ -1480,6 +1480,8 @@ <java-symbol type="style" name="Theme.Dialog.AppError" /> <java-symbol type="style" name="Theme.Toast" /> <java-symbol type="xml" name="storage_list" /> + <java-symbol type="bool" name="config_enableDreams" /> + <java-symbol type="string" name="config_defaultDreamComponent" /> <!-- From SystemUI --> <java-symbol type="anim" name="push_down_in" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index bc5b1bc..18ee2f8 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -219,6 +219,12 @@ please see styles_device_defaults.xml. <item name="windowExitAnimation">@anim/fade_out</item> </style> + <!-- Window animations for screen savers. {@hide} --> + <style name="Animation.Dream"> + <item name="windowEnterAnimation">@anim/slow_fade_in</item> + <item name="windowExitAnimation">@anim/fast_fade_out</item> + </style> + <!-- Status Bar Styles --> <style name="TextAppearance.StatusBar"> <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index f3622ef..d150b5c 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -65,6 +65,7 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.telephony.ITelephony; import com.android.internal.widget.PointerLocationView; +import android.service.dreams.IDreamManager; import android.speech.RecognizerIntent; import android.util.DisplayMetrics; import android.util.EventLog; @@ -108,6 +109,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_DRAG; +import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; @@ -202,26 +204,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { // responsible for power management when displayed. static final int KEYGUARD_LAYER = 11; static final int KEYGUARD_DIALOG_LAYER = 12; - static final int STATUS_BAR_SUB_PANEL_LAYER = 13; - static final int STATUS_BAR_LAYER = 14; - static final int STATUS_BAR_PANEL_LAYER = 15; + // used for Dreams (screensavers with TYPE_DREAM windows) + static final int SCREENSAVER_LAYER = 13; + static final int STATUS_BAR_SUB_PANEL_LAYER = 14; + static final int STATUS_BAR_LAYER = 15; + static final int STATUS_BAR_PANEL_LAYER = 16; // the on-screen volume indicator and controller shown when the user // changes the device volume - static final int VOLUME_OVERLAY_LAYER = 16; + static final int VOLUME_OVERLAY_LAYER = 17; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 17; + static final int SYSTEM_OVERLAY_LAYER = 18; // the navigation bar, if available, shows atop most things - static final int NAVIGATION_BAR_LAYER = 18; + static final int NAVIGATION_BAR_LAYER = 19; // system-level error dialogs - static final int SYSTEM_ERROR_LAYER = 19; + static final int SYSTEM_ERROR_LAYER = 20; // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - static final int DRAG_LAYER = 20; - static final int SECURE_SYSTEM_OVERLAY_LAYER = 21; - static final int BOOT_PROGRESS_LAYER = 22; + static final int DRAG_LAYER = 21; + static final int SECURE_SYSTEM_OVERLAY_LAYER = 22; + static final int BOOT_PROGRESS_LAYER = 23; // the (mouse) pointer layer - static final int POINTER_LAYER = 23; - static final int HIDDEN_NAV_CONSUMER_LAYER = 24; + static final int POINTER_LAYER = 24; + static final int HIDDEN_NAV_CONSUMER_LAYER = 25; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -453,6 +457,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mLockScreenTimerActive; // visual screen saver support + boolean mScreenSaverFeatureAvailable; int mScreenSaverTimeout = 0; boolean mScreenSaverEnabledByUser = false; boolean mScreenSaverMayRun = true; // false if a wakelock is held @@ -1076,6 +1081,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation = true; } + // dreams + mScreenSaverFeatureAvailable = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enableDreams); + mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver, Settings.Secure.SCREENSAVER_ENABLED, 1); @@ -1091,7 +1100,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenSaverTimeout -= 5000; } } - updateScreenSaverTimeoutLocked(); } if (updateRotation) { updateRotation(true); @@ -1179,6 +1187,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // this... should introduce a token to let the system // monitor/control what they are doing. break; + case TYPE_DREAM: case TYPE_INPUT_METHOD: case TYPE_WALLPAPER: // The window manager will check these. @@ -1309,6 +1318,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return BOOT_PROGRESS_LAYER; case TYPE_HIDDEN_NAV_CONSUMER: return HIDDEN_NAV_CONSUMER_LAYER; + case TYPE_DREAM: + return SCREENSAVER_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -3330,7 +3341,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { updateOrientationListenerLp(); updateLockScreenTimeout(); - updateScreenSaverTimeoutLocked(); } } @@ -3379,7 +3389,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOnEarly = true; updateOrientationListenerLp(); updateLockScreenTimeout(); - updateScreenSaverTimeoutLocked(); } } @@ -3769,83 +3778,58 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); } } + } - synchronized (mLock) { - // Only posts messages; holds no additional locks. - updateScreenSaverTimeoutLocked(); + private IDreamManager getDreamManager() { + if (!mScreenSaverFeatureAvailable) { + return null; } + + IDreamManager sandman = IDreamManager.Stub.asInterface( + ServiceManager.checkService("dreams")); + if (sandman == null) { + Log.w(TAG, "Unable to find IDreamManager"); + } + return sandman; } - Runnable mScreenSaverActivator = new Runnable() { - public void run() { - if (!(mScreenSaverMayRun && mScreenOnEarly)) { - Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?"); - return; - } - if (!mPluggedIn) { - if (localLOGV) Log.v(TAG, "mScreenSaverActivator: not running screen saver when not plugged in"); - return; - } - // Quick fix for automation tests. - // The correct fix is to move this triggering logic to PowerManager, where more complete - // information about wakelocks (including StayOnWhilePluggedIn) is available. - if (Settings.System.getInt(mContext.getContentResolver(), - Settings.System.STAY_ON_WHILE_PLUGGED_IN, - BatteryManager.BATTERY_PLUGGED_AC) != 0) { - Log.v(TAG, "mScreenSaverActivator: not running screen saver when STAY_ON_WHILE_PLUGGED_IN"); - return; - } + @Override + public boolean isScreenSaverEnabled() { + return (mScreenSaverFeatureAvailable && mScreenSaverEnabledByUser + && mScreenSaverMayRun && mScreenOnEarly && mPluggedIn); + } - if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland"); + @Override + public boolean startScreenSaver() { + synchronized (mLock) { + if (isScreenSaverEnabled()) { + IDreamManager dm = getDreamManager(); + if (dm == null) return false; + + try { + if (localLOGV) Log.v(TAG, "startScreenSaver: entering dreamland..."); - try { - String component = Settings.Secure.getString( - mContext.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT); - if (component == null) { - component = mContext.getResources().getString(R.string.config_defaultDreamComponent); + dm.dream(); + return true; + } catch (RemoteException ex) { + // too bad, so sad, oh mom, oh dad } - if (component != null) { - // dismiss the notification shade, recents, etc. - mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)); - - ComponentName cn = ComponentName.unflattenFromString(component); - Intent intent = new Intent(Intent.ACTION_MAIN) - .setComponent(cn) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_NO_USER_ACTION - | Intent.FLAG_FROM_BACKGROUND - | Intent.FLAG_ACTIVITY_NO_HISTORY - ); - mContext.startActivity(intent); - } else { - Log.e(TAG, "Couldn't start screen saver: none selected"); - } - } catch (android.content.ActivityNotFoundException exc) { - // no screensaver? give up - Log.e(TAG, "Couldn't start screen saver: none installed"); } } - }; - - // Must call while holding mLock - private void updateScreenSaverTimeoutLocked() { - if (mScreenSaverActivator == null) return; + return false; + } - mHandler.removeCallbacks(mScreenSaverActivator); - if (mScreenSaverEnabledByUser && mScreenSaverMayRun && mScreenOnEarly && mScreenSaverTimeout > 0) { - if (localLOGV) - Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now"); - mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout); - } else { - if (localLOGV) { - if (!mScreenSaverEnabledByUser || mScreenSaverTimeout == 0) - Log.v(TAG, "screen saver disabled by user"); - else if (!mScreenOnEarly) - Log.v(TAG, "screen saver disabled while screen off"); - else - Log.v(TAG, "screen saver disabled by wakelock"); + @Override + public void stopScreenSaver() { + synchronized (mLock) { + IDreamManager dm = getDreamManager(); + if (dm == null) return; + + try { + if (localLOGV) Log.v(TAG, "startScreenSaver: awakening..."); + + dm.awaken(); + } catch (RemoteException ex) { } } } @@ -4091,7 +4075,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // even if the keyguard is up, now that all the wakelocks have been released, we // should re-enable the screen saver mScreenSaverMayRun = true; - updateScreenSaverTimeoutLocked(); } } } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 52a4110..bebce7e 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1752,7 +1752,7 @@ public class PowerManagerService extends IPowerManager.Stub + " noChangeLights=" + noChangeLights + " reason=" + reason); } - + if (noChangeLights) { newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK); } @@ -1794,6 +1794,19 @@ public class PowerManagerService extends IPowerManager.Stub final boolean stateChanged = mPowerState != newState; + if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) { + if (mPolicy.isScreenSaverEnabled()) { + if (mSpew) { + Slog.d(TAG, "setPowerState: running screen saver instead of turning off screen"); + } + if (mPolicy.startScreenSaver()) { + // was successful + return; + } + } + } + + if (oldScreenOn != newScreenOn) { if (newScreenOn) { // When the user presses the power button, we need to always send out the diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 7dd736d..68bbb571 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -38,6 +38,7 @@ import android.provider.Settings; import android.server.BluetoothA2dpService; import android.server.BluetoothService; import android.server.search.SearchManagerService; +import android.service.dreams.DreamManagerService; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -269,6 +270,7 @@ class ServerThread extends Thread { CountryDetectorService countryDetector = null; TextServicesManagerService tsms = null; LockSettingsService lockSettings = null; + DreamManagerService dreamy = null; // Bring up services needed for UI. if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { @@ -613,6 +615,18 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("starting CommonTimeManagementService service", e); } + + if (context.getResources().getBoolean( + com.android.internal.R.bool.config_enableDreams)) { + try { + Slog.i(TAG, "Dreams Service"); + // Dreams (interactive idle-time views, a/k/a screen savers) + dreamy = new DreamManagerService(context); + ServiceManager.addService("dreams", dreamy); + } catch (Throwable e) { + reportWtf("starting DreamManagerService", e); + } + } } // Before things start rolling, be sure we have decided whether @@ -699,6 +713,7 @@ class ServerThread extends Thread { final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService; final TextServicesManagerService textServiceManagerServiceF = tsms; final StatusBarManagerService statusBarF = statusBar; + final DreamManagerService dreamyF = dreamy; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -805,6 +820,11 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("making Text Services Manager Service ready", e); } + try { + if (dreamyF != null) dreamyF.systemReady(); + } catch (Throwable e) { + reportWtf("making DreamManagerService ready", e); + } } }); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index a7af8fb..00972fa 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -28,6 +28,7 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -2131,6 +2132,11 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerImpl.ADD_BAD_APP_TOKEN; } + if (attrs.type == TYPE_DREAM) { + Slog.w(TAG, "Attempted to add Dream window with unknown token " + + attrs.token + ". Aborting."); + return WindowManagerImpl.ADD_BAD_APP_TOKEN; + } token = new WindowToken(this, attrs.token, -1, false); addToken = true; } else if (attrs.type >= FIRST_APPLICATION_WINDOW @@ -2163,6 +2169,12 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerImpl.ADD_BAD_APP_TOKEN; } + } else if (attrs.type == TYPE_DREAM) { + if (token.windowType != TYPE_DREAM) { + Slog.w(TAG, "Attempted to add Dream window with bad token " + + attrs.token + ". Aborting."); + return WindowManagerImpl.ADD_BAD_APP_TOKEN; + } } win = new WindowState(this, session, client, token, |