Merge "Framework support for Android Dreams."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8ee18f7..c78b935 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3744,6 +3744,23 @@
                 "setup_prepaid_detection_redir_host";
 
         /**
+         * The user's preferred "dream" (interactive screensaver) component.
+         *
+         * This component will be launched by the PhoneWindowManager after the user's chosen idle
+         * timeout (specified by {@link #DREAM_TIMEOUT}).
+         * @hide
+         */
+        public static final String DREAM_COMPONENT =
+                "dream_component";
+
+        /**
+         * The delay before a "dream" is started (set to 0 to disable).
+         * @hide
+         */
+        public static final String DREAM_TIMEOUT =
+                "dream_timeout";
+
+        /**
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 4e52e40..64b1ac8 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -884,7 +884,13 @@
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
     
     /**
-     * Called when we have stopped keeping the screen on because a window
+     * Called when we have started keeping the screen on because a window
+     * requesting this has become visible.
+     */
+    public void screenOnStartedLw();
+
+    /**
+     * Called when we have stopped keeping the screen on because the last window
      * requesting this is no longer visible.
      */
     public void screenOnStoppedLw();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index e5abeac..e48dbe9 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -23,6 +23,7 @@
 import android.app.UiModeManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -344,6 +345,10 @@
     int mLockScreenTimeout;
     boolean mLockScreenTimerActive;
 
+    // visual screen saver support
+    int mScreenSaverTimeout;
+    boolean mScreenSaverEnabled = false;
+
     // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
     int mEndcallBehavior;
 
@@ -399,6 +404,8 @@
                     Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     "fancy_rotation_anim"), false, this);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.Secure.DREAM_TIMEOUT), false, this);
             updateSettings();
         }
 
@@ -832,6 +839,11 @@
                 mHasSoftInput = hasSoftInput;
                 updateRotation = true;
             }
+
+            mScreenSaverTimeout = Settings.System.getInt(resolver,
+                    Settings.Secure.DREAM_TIMEOUT, 0);
+            mScreenSaverEnabled = true;
+            updateScreenSaverTimeoutLocked();
         }
         if (updateRotation) {
             updateRotation(0);
@@ -2603,6 +2615,7 @@
             mScreenOn = false;
             updateOrientationListenerLp();
             updateLockScreenTimeout();
+            updateScreenSaverTimeoutLocked();
         }
     }
 
@@ -2614,6 +2627,7 @@
             mScreenOn = true;
             updateOrientationListenerLp();
             updateLockScreenTimeout();
+            updateScreenSaverTimeoutLocked();
         }
     }
 
@@ -2894,6 +2908,63 @@
                 mStatusBarService.userActivity();
             } catch (RemoteException ex) {}
         }
+
+        synchronized (mLock) {
+            updateScreenSaverTimeoutLocked();
+        }
+    }
+
+    Runnable mScreenSaverActivator = new Runnable() {
+        public void run() {
+            synchronized (this) {
+                if (!(mScreenSaverEnabled && mScreenOn)) {
+                    Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?");
+                    return;
+                }
+
+                if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland");
+                try {
+                    String component = Settings.System.getString(
+                            mContext.getContentResolver(), Settings.Secure.DREAM_COMPONENT);
+                    if (component != null) {
+                        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_ACTIVITY_SINGLE_TOP);
+                        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() {
+        synchronized (mScreenSaverActivator) {
+            mHandler.removeCallbacks(mScreenSaverActivator);
+            if (mScreenSaverEnabled && mScreenOn && mScreenSaverTimeout > 0) {
+                if (localLOGV)
+                    Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now");
+                mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout);
+            } else {
+                if (localLOGV) {
+                    if (mScreenSaverTimeout == 0)
+                        Log.v(TAG, "screen saver disabled by user");
+                    else if (!mScreenOn)
+                        Log.v(TAG, "screen saver disabled while screen off");
+                    else
+                        Log.v(TAG, "screen saver disabled by wakelock");
+                }
+            }
+        }
     }
 
     Runnable mScreenLockTimeout = new Runnable() {
@@ -3089,10 +3160,27 @@
         return true;
     }
     
+    public void screenOnStartedLw() {
+        // The window manager has just grabbed a wake lock. This is our cue to disable the screen
+        // saver.
+        synchronized (mLock) {
+            mScreenSaverEnabled = false;
+        }
+    }
+
     public void screenOnStoppedLw() {
-        if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) {
-            long curTime = SystemClock.uptimeMillis();
-            mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
+        if (mPowerManager.isScreenOn()) {
+            if (!mKeyguardMediator.isShowingAndNotHidden()) {
+                long curTime = SystemClock.uptimeMillis();
+                mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
+            }
+
+            synchronized (mLock) {
+                // even if the keyguard is up, now that all the wakelocks have been released, we
+                // should re-enable the screen saver
+                mScreenSaverEnabled = true;
+                updateScreenSaverTimeoutLocked();
+            }
         }
     }
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 79dbfd6..08fea1b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -8297,6 +8297,7 @@
         boolean state = mHoldingScreenWakeLock.isHeld();
         if (holding != state) {
             if (holding) {
+                mPolicy.screenOnStartedLw();
                 mHoldingScreenWakeLock.acquire();
             } else {
                 mPolicy.screenOnStoppedLw();