New Android Dreams architecture, disabled for now.

Rather than normal Activities (which have a host of problems
when used for this purpose), screen savers are now a
special kind of Service that can add views to its own
special window (TYPE_DREAM, in the SCREENSAVER layer).

Dreams are now launched by the power manager; whenever it is
about to turn the screen off, it asks the window manager if
it wants to run a screen saver instead. (http://b/5677408)

Also, the new config_enableDreams bool allows the entire
feature to be switched on or off in one place. It is
currently switched off (and the APIs are all @hidden).

Change-Id: Idfe9d430568471d15f4b463cb70586a899a331f7
diff --git a/Android.mk b/Android.mk
index 9c51fc6..cacdee9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -132,6 +132,8 @@
 	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 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 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 baeb9cc..2eeb067 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -219,6 +219,12 @@
         <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 5697284..f1e571f 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.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_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 @@
     // 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 @@
     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 @@
                 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 @@
                     mScreenSaverTimeout -= 5000;
                 }
             }
-            updateScreenSaverTimeoutLocked();
         }
         if (updateRotation) {
             updateRotation(true);
@@ -1179,6 +1187,7 @@
                 // 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 @@
             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;
@@ -3317,7 +3328,6 @@
         synchronized (mLock) {
             updateOrientationListenerLp();
             updateLockScreenTimeout();
-            updateScreenSaverTimeoutLocked();
         }
     }
 
@@ -3366,7 +3376,6 @@
             mScreenOnEarly = true;
             updateOrientationListenerLp();
             updateLockScreenTimeout();
-            updateScreenSaverTimeoutLocked();
         }
     }
 
@@ -3756,83 +3765,58 @@
                 mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
             }
         }
-
-        synchronized (mLock) {
-            // Only posts messages; holds no additional locks.
-            updateScreenSaverTimeoutLocked();
-        }
     }
 
-    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;
-            }
+    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;
+    }
 
-            if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
+    @Override
+    public boolean isScreenSaverEnabled() {
+        return (mScreenSaverFeatureAvailable && mScreenSaverEnabledByUser
+                && mScreenSaverMayRun && mScreenOnEarly && mPluggedIn);
+    }
 
-            try {
-                String component = Settings.Secure.getString(
-                        mContext.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT);
-                if (component == null) {
-                    component = mContext.getResources().getString(R.string.config_defaultDreamComponent);
+    @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...");
+
+                    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");
             }
         }
-    };
+        return false;
+    }
 
-    // Must call while holding mLock
-    private void updateScreenSaverTimeoutLocked() {
-        if (mScreenSaverActivator == null) return;
-
-        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) {
             }
         }
     }
@@ -4078,7 +4062,6 @@
                 // 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 @@
                         + " noChangeLights=" + noChangeLights
                         + " reason=" + reason);
             }
-
+            
             if (noChangeLights) {
                 newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
             }
@@ -1794,6 +1794,19 @@
 
             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.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 @@
         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 @@
             } 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 @@
         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 @@
                 } 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 6f7852d..5fa8111 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_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 @@
                           + 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 @@
                             + 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,