Make DreamManagerService more robust.

Clearly isolated the DreamManagerService and DreamController
responsibilities.  DreamManagerService contains just enough logic to
manage the global synchronous behaviors.  All of the asynchronous
behaviors are in DreamController.

Added a new PowerManager function called nap() to request the device
to start napping.  If it is a good time to nap, then the
PowerManagerService will call startDream() on the DreamManagerService
to start dreaming.

Fixed a possible multi-user issue by explicitly tracking for
which user a dream service is being started and stopping dreams
when the current user changes.  The user id is also passed to
bindService() to ensure that the dream has the right environment.

Fix interactions with docks and the UI mode manager.  It is
important that we always send the ACTION_DOCK_EVENT broadcast
to the system so that it can configure audio routing and the like.
When docked, the UI mode manager starts a dock app if there is
one, otherwise it starts a dream.

This change resolves issues with dreams started for reasons other
than a user activity timeout.

Bug: 7204211
Change-Id: I3193cc8190982c0836319176fa2e9c4dcad9c01f
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 8ad5a91..4a8bf72 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,9 +16,6 @@
 
 package com.android.server;
 
-import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
-import static android.provider.Settings.Secure.SCREENSAVER_ENABLED;
-
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -27,16 +24,12 @@
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.dreams.IDreamManager;
 import android.util.Log;
 import android.util.Slog;
 
@@ -48,14 +41,10 @@
  */
 final class DockObserver extends UEventObserver {
     private static final String TAG = DockObserver.class.getSimpleName();
-    private static final boolean LOG = false;
 
     private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
     private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
 
-    private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
-    private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
     private static final int MSG_DOCK_STATE_CHANGED = 0;
 
     private final Object mLock = new Object();
@@ -66,11 +55,16 @@
     private boolean mSystemReady;
 
     private final Context mContext;
+    private final PowerManager mPowerManager;
+    private final PowerManager.WakeLock mWakeLock;
 
     public DockObserver(Context context) {
         mContext = context;
-        init();  // set initial status
 
+        mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+        init();  // set initial status
         startObserving(DOCK_UEVENT_MATCH);
     }
 
@@ -87,17 +81,9 @@
                     mPreviousDockState = mDockState;
                     mDockState = newState;
                     if (mSystemReady) {
-                        // Don't force screen on when undocking from the desk dock.
-                        // The change in power state will do this anyway.
-                        // FIXME - we should be configurable.
-                        if ((mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK
-                                && mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK
-                                && mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) ||
-                                mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                            PowerManager pm =
-                                    (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-                            pm.wakeUp(SystemClock.uptimeMillis());
-                        }
+                        // Wake up immediately when docked or undocked.
+                        mPowerManager.wakeUp(SystemClock.uptimeMillis());
+
                         updateLocked();
                     }
                 }
@@ -138,6 +124,7 @@
     }
 
     private void updateLocked() {
+        mWakeLock.acquire();
         mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
     }
 
@@ -145,8 +132,8 @@
         synchronized (mLock) {
             Slog.i(TAG, "Dock state changed: " + mDockState);
 
+            // Skip the dock intent if not yet provisioned.
             final ContentResolver cr = mContext.getContentResolver();
-
             if (Settings.Global.getInt(cr,
                     Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
                 Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
@@ -158,16 +145,8 @@
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
             intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
 
-            // Check if this is Bluetooth Dock
-            // TODO(BT): Get Dock address.
-            // String address = null;
-            // if (address != null) {
-            //    intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
-            //            BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
-            // }
-
-            // User feedback to confirm dock connection. Particularly
-            // useful for flaky contact pins...
+            // Play a sound to provide feedback to confirm dock connection.
+            // Particularly useful for flaky contact pins...
             if (Settings.Global.getInt(cr,
                     Settings.Global.DOCK_SOUNDS_ENABLED, 1) == 1) {
                 String whichSound = null;
@@ -204,44 +183,16 @@
                 }
             }
 
-            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 {
-                    if (isScreenSaverEnabled(mContext) && isScreenSaverActivatedOnDock(mContext)) {
-                        try {
-                            mgr.dream();
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "Unable to dream!", e);
-                        }
-                    }
-                }
-            } else {
-                // dreams feature not enabled, send legacy intent
-                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-            }
+            // Send the dock event intent.
+            // There are many components in the system watching for this so as to
+            // adjust audio routing, screen orientation, etc.
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+
+            // Release the wake lock that was acquired when the message was posted.
+            mWakeLock.release();
         }
     }
 
-    private static boolean isScreenSaverEnabled(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED) != 0;
-    }
-
-    private static boolean isScreenSaverActivatedOnDock(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK) != 0;
-    }
-
     private final Handler mHandler = new Handler(true /*async*/) {
         @Override
         public void handleMessage(Message msg) {