Re-enable dreams: frameworks/base

Enable feature in config. Expose Dream in public api for unbundled apps.
Unhide package.  Add isDreaming() method to service.

Re-arrange the Dream api a bit.  (use onStart as hook for subclasses).
Coordinate properly with power manager.

Replace old dock mode (don't fire old intent).

Change-Id: I1318d20cc1613e5d862f2913f2fcdc9719302cf7
Bug: 6921930
diff --git a/api/current.txt b/api/current.txt
index 4b43318..cc67e89 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19927,6 +19927,50 @@
 
 }
 
+package android.service.dreams {
+
+  public class Dream extends android.app.Service implements android.view.Window.Callback {
+    ctor public Dream();
+    method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
+    method public boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public boolean dispatchTouchEvent(android.view.MotionEvent);
+    method public boolean dispatchTrackballEvent(android.view.MotionEvent);
+    method public android.view.View findViewById(int);
+    method public void finish();
+    method public android.view.Window getWindow();
+    method public android.view.WindowManager getWindowManager();
+    method public boolean isInteractive();
+    method protected void lightsOut();
+    method public void onActionModeFinished(android.view.ActionMode);
+    method public void onActionModeStarted(android.view.ActionMode);
+    method public void onAttachedToWindow();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onContentChanged();
+    method public boolean onCreatePanelMenu(int, android.view.Menu);
+    method public android.view.View onCreatePanelView(int);
+    method public void onDetachedFromWindow();
+    method public boolean onMenuItemSelected(int, android.view.MenuItem);
+    method public boolean onMenuOpened(int, android.view.Menu);
+    method public void onPanelClosed(int, android.view.Menu);
+    method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+    method public boolean onSearchRequested();
+    method public void onStart();
+    method public final int onStartCommand(android.content.Intent, int, int);
+    method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public void onWindowFocusChanged(boolean);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public void setContentView(int);
+    method public void setContentView(android.view.View);
+    method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public void setInteractive(boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.Dream";
+  }
+
+}
+
 package android.service.textservice {
 
   public abstract class SpellCheckerService extends android.app.Service {
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index 83464c9..9a903e4 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -1,26 +1,31 @@
 /**
- * 
+ * 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 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;
@@ -28,14 +33,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+
+import com.android.internal.policy.PolicyManager;
 
 /**
- * @hide
- *
+ *  Extend this class to implement a custom screensaver.
  */
 public class Dream extends Service implements Window.Callback {
     private final static boolean DEBUG = true;
@@ -61,7 +66,7 @@
     final Handler mHandler = new Handler();
     
     boolean mFinished = false;
-    
+
     // begin Window.Callback methods
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
@@ -210,19 +215,14 @@
 
         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 
+     * Called when this Dream is started.
      */
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        return super.onStartCommand(intent, flags, startId);
+    public void onStart() {
+        // hook for subclasses
     }
-    
+
    /**
      * Inflate a layout resource and set it to be the content view for this Dream.
      * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
@@ -351,9 +351,12 @@
             @Override
             public void run() {
                 if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId());
-                
+
                 getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
-            }});        
+
+                // start it up
+                onStart();
+            }});
     }
     
     /**
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index 4a14ced..d6b38a1 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -114,11 +114,19 @@
         if (DEBUG) Slog.v(TAG, "awaken()");
         synchronized (mLock) {
             if (mCurrentDream != null) {
+                if (DEBUG) Slog.v(TAG, "disconnecting: " +  mCurrentDreamComponent + " service: " + mCurrentDream);
                 mContext.unbindService(this);
+                mCurrentDream = null;
+                mCurrentDreamToken = null;
             }
         }
     }
 
+    // IDreamManager method
+    public boolean isDreaming() {
+        return mCurrentDream != null;
+    }
+
     public void bindDreamComponentL(ComponentName componentName, boolean test) {
         if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName
                 + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -129,11 +137,7 @@
                 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 {
@@ -145,6 +149,9 @@
             Slog.w(TAG, "Unable to add window token. Proceed at your own risk.");
         }
         
+        if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+            Slog.w(TAG, "unable to bind service: " + componentName);
+        }
     }
 
     @Override
@@ -163,8 +170,7 @@
     @Override
     public void onServiceDisconnected(ComponentName name) {
         if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream);
-        mCurrentDream = null;
-        mCurrentDreamToken = null;
+        // Only happens in exceptional circumstances
     }
     
     @Override
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 7225013..b64dd8f 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -27,4 +27,5 @@
     void setDreamComponent(in ComponentName componentName);
     ComponentName getDreamComponent();
     void testDream(in ComponentName componentName);
+    boolean isDreaming();
 }
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 39129e5..b752471 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -852,7 +852,7 @@
     <string name="config_wimaxStateTrackerClassname" translatable="false"></string>
 
     <!-- enable screen saver feature -->
-    <bool name="config_enableDreams">false</bool>
+    <bool name="config_enableDreams">true</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/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 97b4cb5..215f597 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1132,7 +1132,7 @@
                     com.android.internal.R.bool.config_enableDreams);
             
             mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver,
-                    Settings.Secure.SCREENSAVER_ENABLED, 1);
+                    Settings.Secure.SCREENSAVER_ENABLED, 0);
 
             if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
                 mScreenSaverTimeout = Settings.Secure.getInt(resolver,
@@ -4076,7 +4076,9 @@
             if (dm == null) return;
             
             try {
-                if (localLOGV) Log.v(TAG, "startScreenSaver: awakening...");
+                if (!dm.isDreaming()) return;
+
+                if (localLOGV) Log.v(TAG, "stopScreenSaver: awakening...");
                 
                 dm.awaken();
             } catch (RemoteException ex) {
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index e7dac72..8bac52c 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -29,9 +29,12 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.provider.Settings;
+import android.service.dreams.IDreamManager;
 import android.util.Log;
 import android.util.Slog;
 
@@ -194,7 +197,29 @@
                             }
                         }
 
-                        mContext.sendStickyBroadcast(intent);
+                        IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
+                        if (mgr != null) {
+                            // dreams feature enabled
+                            boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED;
+                            if (undocked) {
+                                try {
+                                    if (mgr.isDreaming()) {
+                                        mgr.awaken();
+                                    }
+                                } catch (RemoteException e) {
+                                    Slog.w(TAG, "Unable to awaken!", e);
+                                }
+                            } else {
+                                try {
+                                    mgr.dream();
+                                } catch (RemoteException e) {
+                                    Slog.w(TAG, "Unable to dream!", e);
+                                }
+                            }
+                        } else {
+                            // dreams feature not enabled, send legacy intent
+                            mContext.sendStickyBroadcast(intent);
+                        }
                     }
                     break;
             }
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 453c7a4..cb6db3c 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -424,6 +424,11 @@
                             forceUserActivityLocked();
                         }
                     }
+
+                    // stop the screensaver if we're now unplugged
+                    if (mPolicy != null) {
+                        mPolicy.stopScreenSaver();
+                    }
                 }
             }
         }
@@ -1826,7 +1831,7 @@
             final boolean stateChanged = mPowerState != newState;
 
             if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) {
-                if (mPolicy != null && mPolicy.isScreenSaverEnabled()) {
+                if (mPolicy != null && mPolicy.isScreenSaverEnabled() && mIsPowered) {
                     if (DEBUG) {
                         Slog.d(TAG, "setPowerState: running screen saver instead of turning off screen");
                     }
@@ -1922,6 +1927,13 @@
                     } else {
                         err = 0;
                     }
+
+                    // stop the screensaver if user turned screen off
+                    if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
+                        if (mPolicy != null) {
+                            mPolicy.stopScreenSaver();
+                        }
+                    }
                 }
             } else if (stateChanged) {
                 // Screen on/off didn't change, but lights may have.