Do not launch Somnambulator as a dock app.

Fixes a black flash that occurred when the device was docked
because the UiModeManagerService was launching the Somnambulator
to start the dream when docked.  This caused an unnecessary
activity transition and could in fact make dreaming less
reliable than if the UiModeManagerService started the dream itself.

Moved common code from UiModeManagerService and Somnambulator
to Sandman to ensure it is kept in sync.

Bug: 7328545
Change-Id: I46102784e2ab1acc0241d43a48abf0581278af24
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
new file mode 100644
index 0000000..70142ce
--- /dev/null
+++ b/core/java/android/service/dreams/Sandman.java
@@ -0,0 +1,122 @@
+/*
+ * 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.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+
+/**
+ * Internal helper for launching dreams to ensure consistency between the
+ * <code>UiModeManagerService</code> system service and the <code>Somnambulator</code> activity.
+ *
+ * @hide
+ */
+public final class Sandman {
+    private static final String TAG = "Sandman";
+
+    private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
+    private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
+
+    // The component name of a special dock app that merely launches a dream.
+    // We don't want to launch this app when docked because it causes an unnecessary
+    // activity transition.  We just want to start the dream.
+    private static final ComponentName SOMNAMBULATOR_COMPONENT =
+            new ComponentName("com.android.systemui", "com.android.systemui.Somnambulator");
+
+
+    // The sandman is eternal.  No one instantiates him.
+    private Sandman() {
+    }
+
+    /**
+     * Returns true if the specified dock app intent should be started.
+     * False if we should dream instead, if appropriate.
+     */
+    public static boolean shouldStartDockApp(Context context, Intent intent) {
+        ComponentName name = intent.resolveActivity(context.getPackageManager());
+        return name != null && !name.equals(SOMNAMBULATOR_COMPONENT);
+    }
+
+    /**
+     * Starts a dream manually.
+     */
+    public static void startDreamByUserRequest(Context context) {
+        startDream(context, false);
+    }
+
+    /**
+     * Starts a dream when docked if the system has been configured to do so,
+     * otherwise does nothing.
+     */
+    public static void startDreamWhenDockedIfAppropriate(Context context) {
+        if (!isScreenSaverEnabled(context)
+                || !isScreenSaverActivatedOnDock(context)) {
+            Slog.i(TAG, "Dreams currently disabled for docks.");
+            return;
+        }
+
+        startDream(context, true);
+    }
+
+    private static void startDream(Context context, boolean docked) {
+        try {
+            IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
+                    ServiceManager.getService(DreamService.DREAM_SERVICE));
+            if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
+                if (docked) {
+                    Slog.i(TAG, "Activating dream while docked.");
+
+                    // Wake up.
+                    // The power manager will wake up the system automatically when it starts
+                    // receiving power from a dock but there is a race between that happening
+                    // and the UI mode manager starting a dream.  We want the system to already
+                    // be awake by the time this happens.  Otherwise the dream may not start.
+                    PowerManager powerManager =
+                            (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+                    powerManager.wakeUp(SystemClock.uptimeMillis());
+                } else {
+                    Slog.i(TAG, "Activating dream by user request.");
+                }
+
+                // Dream.
+                dreamManagerService.dream();
+            }
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Could not start dream when docked.", ex);
+        }
+    }
+
+    private static boolean isScreenSaverEnabled(Context context) {
+        return Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
+                UserHandle.USER_CURRENT) != 0;
+    }
+
+    private static boolean isScreenSaverActivatedOnDock(Context context) {
+        return Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+                DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
index 9356ff2..0dd6d92 100644
--- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java
+++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
@@ -1,4 +1,4 @@
-/*);
+/*
  * Copyright (C) 2012 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,38 +18,23 @@
 
 import android.app.Activity;
 import android.content.Intent;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
-import android.util.Slog;
+import android.service.dreams.Sandman;
 
+/**
+ * A simple activity that launches a dream.
+ * <p>
+ * Note: This Activity is special.  If this class is moved to another package or
+ * renamed, be sure to update the component name in {@link Sandman}.
+ * </p>
+ */
 public class Somnambulator extends Activity {
-    public static final String TAG = "Somnambulator";
-
-    public static final int DEFAULT_SCREENSAVER_ENABLED = 1;
-    public static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
     public Somnambulator() {
     }
 
-    private boolean isScreenSaverEnabled() {
-        return Settings.Secure.getIntForUser(getContentResolver(),
-                Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
-                UserHandle.USER_CURRENT) != 0;
-    }
-
-    private boolean isScreenSaverActivatedOnDock() {
-        return Settings.Secure.getIntForUser(getContentResolver(),
-                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
-                DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
-    }
-
     @Override
     public void onStart() {
         super.onStart();
+
         final Intent launchIntent = getIntent();
         final String action = launchIntent.getAction();
         if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
@@ -64,23 +49,12 @@
             setResult(RESULT_OK, resultIntent);
         } else {
             boolean docked = launchIntent.hasCategory(Intent.CATEGORY_DESK_DOCK);
-
-            if (docked && !(isScreenSaverEnabled() && isScreenSaverActivatedOnDock())) {
-                Slog.i(TAG, "Dreams currently disabled for docks.");
+            if (docked) {
+                Sandman.startDreamWhenDockedIfAppropriate(this);
             } else {
-                IDreamManager somnambulist = IDreamManager.Stub.asInterface(
-                        ServiceManager.checkService(DreamService.DREAM_SERVICE));
-                if (somnambulist != null) {
-                    try {
-                        Slog.v(TAG, "Dreaming on " + (docked ? "dock insertion" : "user request"));
-                        somnambulist.dream();
-                    } catch (RemoteException e) {
-                        // fine, stay asleep then
-                    }
-                }
+                Sandman.startDreamByUserRequest(this);
             }
         }
         finish();
     }
-
 }
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 2d4eb79..0e456f1 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -37,11 +37,9 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
+import android.service.dreams.Sandman;
 import android.util.Slog;
 
 import java.io.FileDescriptor;
@@ -59,9 +57,6 @@
     private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
     private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
 
-    private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
-    private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
     private final Context mContext;
     private final TwilightService mTwilightService;
     private final Handler mHandler = new Handler();
@@ -496,18 +491,20 @@
             // activity manager take care of both the start and config
             // change.
             Intent homeIntent = buildHomeIntent(category);
-            try {
-                int result = ActivityManagerNative.getDefault().startActivityWithConfig(
-                        null, homeIntent, null, null, null, 0, 0,
-                        mConfiguration, null, UserHandle.USER_CURRENT);
-                if (result >= ActivityManager.START_SUCCESS) {
-                    dockAppStarted = true;
-                } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
-                    Slog.e(TAG, "Could not start dock app: " + homeIntent
-                            + ", startActivityWithConfig result " + result);
+            if (Sandman.shouldStartDockApp(mContext, homeIntent)) {
+                try {
+                    int result = ActivityManagerNative.getDefault().startActivityWithConfig(
+                            null, homeIntent, null, null, null, 0, 0,
+                            mConfiguration, null, UserHandle.USER_CURRENT);
+                    if (result >= ActivityManager.START_SUCCESS) {
+                        dockAppStarted = true;
+                    } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
+                        Slog.e(TAG, "Could not start dock app: " + homeIntent
+                                + ", startActivityWithConfig result " + result);
+                    }
+                } catch (RemoteException ex) {
+                    Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
                 }
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
             }
         }
 
@@ -515,41 +512,11 @@
         sendConfigurationLocked();
 
         // If we did not start a dock app, then start dreaming if supported.
-        if (category != null && !dockAppStarted
-                && isScreenSaverEnabledLocked() && isScreenSaverActivatedOnDockLocked()) {
-            Slog.i(TAG, "Activating dream while docked.");
-            try {
-                IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
-                        ServiceManager.getService(DreamService.DREAM_SERVICE));
-                if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
-                    // Wake up.
-                    // The power manager will wake up the system when it starts receiving power
-                    // but there is a race between that happening and the UI mode manager
-                    // starting a dream.  We want the system to already be awake
-                    // by the time this happens.  Otherwise the dream may not start.
-                    mPowerManager.wakeUp(SystemClock.uptimeMillis());
-
-                    // Dream.
-                    dreamManagerService.dream();
-                }
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Could not start dream when docked.", ex);
-            }
+        if (category != null && !dockAppStarted) {
+            Sandman.startDreamWhenDockedIfAppropriate(mContext);
         }
     }
 
-    private boolean isScreenSaverEnabledLocked() {
-        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
-                UserHandle.USER_CURRENT) != 0;
-    }
-
-    private boolean isScreenSaverActivatedOnDockLocked() {
-        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
-                DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
-    }
-
     private void adjustStatusBarCarModeLocked() {
         if (mStatusBarManager == null) {
             mStatusBarManager = (StatusBarManager)