Merge "Set the new SurfaceControl opaque flag." into klp-modular-dev
diff --git a/Android.mk b/Android.mk
index 687989c..7cbc339 100644
--- a/Android.mk
+++ b/Android.mk
@@ -176,6 +176,7 @@
 	core/java/android/print/IWriteResultCallback.aidl \
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
+	core/java/android/service/dreams/IDozeHardware.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
diff --git a/api/current.txt b/api/current.txt
index d0bf458..046775e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7335,6 +7335,7 @@
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
+    field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f6e1f72..45467b8 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -205,7 +205,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -236,7 +236,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -328,7 +328,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent} objects
      * you supply here should almost always be <em>explicit intents</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -378,7 +378,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent} objects
      * you supply here should almost always be <em>explicit intents</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the activity.
@@ -448,7 +448,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should perform
      * the broadcast.
@@ -502,7 +502,7 @@
      * <p class="note">For security reasons, the {@link android.content.Intent}
      * you supply here should almost always be an <em>explicit intent</em>,
      * that is specify an explicit component to be delivered to through
-     * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+     * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
      *
      * @param context The Context in which this PendingIntent should start
      * the service.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 485ee68..ddf0ed6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1249,6 +1249,15 @@
     public static final String FEATURE_TELEVISION = "android.hardware.type.television";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: This is a device dedicated to showing UI
+     * on a watch. A watch here is defined to be a device worn on the body, perhaps on
+     * the wrist. The user is very close when interacting with the device.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_WATCH = "android.hardware.type.watch";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device supports printing.
      */
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 5e0d489..86ef479 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -191,6 +191,18 @@
     public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
 
     /**
+     * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
+     * if no other wake locks are held.
+     * <p>
+     * This is used by the dream manager to implement doze mode.  It currently
+     * has no effect unless the power manager is in the dozing state.
+     * </p>
+     *
+     * {@hide}
+     */
+    public static final int DOZE_WAKE_LOCK = 0x00000040;
+
+    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -418,6 +430,7 @@
             case SCREEN_BRIGHT_WAKE_LOCK:
             case FULL_WAKE_LOCK:
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+            case DOZE_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java
new file mode 100644
index 0000000..b5e7f43
--- /dev/null
+++ b/core/java/android/service/dreams/DozeHardware.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2014 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.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides access to low-level hardware features that a dream may use to provide
+ * a richer user experience while dozing.
+ * <p>
+ * This class contains functions that should be called by the dream to configure
+ * hardware before starting to doze and allowing the application processor to suspend.
+ * For example, the dream may provide the hardware with enough information to render
+ * some content on its own without any further assistance from the application processor.
+ * </p><p>
+ * This object is obtained by calling {@link DreamService#getDozeHardware()}.
+ * </p>
+ *
+ * @hide experimental
+ */
+public final class DozeHardware {
+    private static final String TAG = "DozeHardware";
+
+    public static final String MSG_ENABLE_MCU = "enable_mcu";
+
+    public static final byte[] VALUE_ON = "on".getBytes();
+    public static final byte[] VALUE_OFF = "off".getBytes();
+
+    private final IDozeHardware mHardware;
+
+    DozeHardware(IDozeHardware hardware) {
+        mHardware = hardware;
+    }
+
+    /**
+     * Sets whether to enable the microcontroller.
+     *
+     * @param enable If true, enables the MCU otherwise disables it.
+     */
+    public void setEnableMcu(boolean enable) {
+        sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
+    }
+
+    /**
+     * Sends a message to the doze hardware module.
+     *
+     * @param msg The name of the message to send.
+     * @param arg An optional argument data blob, may be null.
+     * @return A result data blob, may be null.
+     */
+    public byte[] sendMessage(String msg, byte[] arg) {
+        if (msg == null) {
+            throw new IllegalArgumentException("msg must not be null");
+        }
+
+        try {
+            return mHardware.sendMessage(msg, arg);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to send message to doze hardware module.", ex);
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 17ea996..9f7ddba 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -25,7 +25,7 @@
     /**
      * Called by the power manager to start a dream.
      */
-    public abstract void startDream();
+    public abstract void startDream(boolean doze);
 
     /**
      * Called by the power manager to stop a dream.
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index f6b6c89..1abb1d7 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -20,12 +20,14 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.AlarmManager;
 import android.app.Service;
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Slog;
 import android.view.ActionMode;
@@ -42,6 +44,8 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
 
 /**
  * Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -145,19 +149,26 @@
      */
     public static final String DREAM_META_DATA = "android.service.dream";
 
+    private final IDreamManager mSandman;
     private final Handler mHandler = new Handler();
     private IBinder mWindowToken;
     private Window mWindow;
     private WindowManager mWindowManager;
-    private IDreamManager mSandman;
     private boolean mInteractive = false;
     private boolean mLowProfile = true;
     private boolean mFullscreen = false;
     private boolean mScreenBright = true;
     private boolean mFinished;
+    private boolean mCanDoze;
+    private boolean mDozing;
+    private DozeHardware mDozeHardware;
 
     private boolean mDebug = false;
 
+    public DreamService() {
+        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+    }
+
     /**
      * @hide
      */
@@ -444,9 +455,11 @@
      * correct interactions with it (seeing when it is cleared etc).
      */
     public void setLowProfile(boolean lowProfile) {
-        mLowProfile = lowProfile;
-        int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
-        applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+        if (mLowProfile != lowProfile) {
+            mLowProfile = lowProfile;
+            int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+            applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+        }
     }
 
     /**
@@ -467,9 +480,11 @@
      * will be cleared.
      */
     public void setFullscreen(boolean fullscreen) {
-        mFullscreen = fullscreen;
-        int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
-        applyWindowFlags(mFullscreen ? flag : 0, flag);
+        if (mFullscreen != fullscreen) {
+            mFullscreen = fullscreen;
+            int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+            applyWindowFlags(mFullscreen ? flag : 0, flag);
+        }
     }
 
     /**
@@ -487,14 +502,16 @@
      * @param screenBright True to keep the screen bright while dreaming.
      */
     public void setScreenBright(boolean screenBright) {
-        mScreenBright = screenBright;
-        int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-        applyWindowFlags(mScreenBright ? flag : 0, flag);
+        if (mScreenBright != screenBright) {
+            mScreenBright = screenBright;
+            int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+            applyWindowFlags(mScreenBright ? flag : 0, flag);
+        }
     }
 
     /**
-     * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
-     * allowing the screen to dim if necessary.
+     * Returns whether or not this dream keeps the screen bright while dreaming.
+     * Defaults to false, allowing the screen to dim if necessary.
      *
      * @see #setScreenBright(boolean)
      */
@@ -503,6 +520,119 @@
     }
 
     /**
+     * Returns true if this dream is allowed to doze.
+     * <p>
+     * The value returned by this method is only meaningful when the dream has started.
+     * </p>
+     *
+     * @return True if this dream can doze.
+     * @see #startDozing
+     * @hide experimental
+     */
+    public boolean canDoze() {
+        return mCanDoze;
+    }
+
+    /**
+     * Starts dozing, entering a deep dreamy sleep.
+     * <p>
+     * Dozing enables the system to conserve power while the user is not actively interacting
+     * with the device.  While dozing, the display will remain on in a low-power state
+     * and will continue to show its previous contents but the application processor and
+     * other system components will be allowed to suspend when possible.
+     * </p><p>
+     * While the application processor is suspended, the dream may stop executing code
+     * for long periods of time.  Prior to being suspended, the dream may schedule periodic
+     * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
+     * The dream may also keep the CPU awake by acquiring a
+     * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
+     * Note that since the purpose of doze mode is to conserve power (especially when
+     * running on battery), the dream should not wake the CPU very often or keep it
+     * awake for very long.
+     * </p><p>
+     * It is a good idea to call this method some time after the dream's entry animation
+     * has completed and the dream is ready to doze.  It is important to completely
+     * finish all of the work needed before dozing since the application processor may
+     * be suspended at any moment once this method is called unless other wake locks
+     * are being held.
+     * </p><p>
+     * Call {@link #stopDozing} or {@link #finish} to stop dozing.
+     * </p>
+     *
+     * @see #stopDozing
+     * @hide experimental
+     */
+    public void startDozing() {
+        if (mCanDoze && !mDozing) {
+            mDozing = true;
+            try {
+                mSandman.startDozing(mWindowToken);
+            } catch (RemoteException ex) {
+                // system server died
+            }
+        }
+    }
+
+    /**
+     * Stops dozing, returns to active dreaming.
+     * <p>
+     * This method reverses the effect of {@link #startDozing}.  From this moment onward,
+     * the application processor will be kept awake as long as the dream is running
+     * or until the dream starts dozing again.
+     * </p>
+     *
+     * @see #startDozing
+     * @hide experimental
+     */
+    public void stopDozing() {
+        if (mDozing) {
+            mDozing = false;
+            try {
+                mSandman.stopDozing(mWindowToken);
+            } catch (RemoteException ex) {
+                // system server died
+            }
+        }
+    }
+
+    /**
+     * Returns true if the dream will allow the system to enter a low-power state while
+     * it is running without actually turning off the screen.  Defaults to false,
+     * keeping the application processor awake while the dream is running.
+     *
+     * @return True if the dream is dozing.
+     *
+     * @see #setDozing(boolean)
+     * @hide experimental
+     */
+    public boolean isDozing() {
+        return mDozing;
+    }
+
+    /**
+     * Gets an object that may be used to access low-level hardware features that a
+     * dream may use to provide a richer user experience while dozing.
+     *
+     * @return An instance of {@link DozeHardware} or null if this device does not offer
+     * hardware support for dozing.
+     *
+     * @hide experimental
+     */
+    public DozeHardware getDozeHardware() {
+        if (mCanDoze && mDozeHardware == null) {
+            try {
+                IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
+                if (hardware != null) {
+                    mDozeHardware = new DozeHardware(hardware);
+                }
+            } catch (RemoteException ex) {
+                // system server died
+            }
+        }
+        return mDozeHardware;
+    }
+
+    /**
      * Called when this Dream is constructed.
      */
     @Override
@@ -536,7 +666,11 @@
     }
 
     /**
-     * Stops the dream, detaches from the window, and wakes up.
+     * Stops the dream and detaches from the window.
+     * <p>
+     * When the dream ends, the system will be allowed to go to sleep fully unless there
+     * is a reason for it to be awake such as recent user activity or wake locks being held.
+     * </p>
      */
     public final void finish() {
         if (mDebug) Slog.v(TAG, "finish()");
@@ -557,10 +691,6 @@
 
     // end public api
 
-    private void loadSandman() {
-        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
-    }
-
     /**
      * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
      *
@@ -572,23 +702,16 @@
             return;
         }
 
-        try {
-            onDreamingStopped();
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed in onDreamingStopped()", t);
-            // we were going to stop anyway
-        }
+        if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+        onDreamingStopped();
 
         if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
-        try {
-            // force our window to be removed synchronously
-            mWindowManager.removeViewImmediate(mWindow.getDecorView());
-            // the following will print a log message if it finds any other leaked windows
-            WindowManagerGlobal.getInstance().closeAll(mWindowToken,
-                    this.getClass().getName(), "Dream");
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed removing window view", t);
-        }
+
+        // force our window to be removed synchronously
+        mWindowManager.removeViewImmediate(mWindow.getDecorView());
+        // the following will print a log message if it finds any other leaked windows
+        WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+                this.getClass().getName(), "Dream");
 
         mWindow = null;
         mWindowToken = null;
@@ -601,23 +724,30 @@
      *
      * @param windowToken A window token that will allow a window to be created in the correct layer.
      */
-    private final void attach(IBinder windowToken) {
+    private final void attach(IBinder windowToken, boolean canDoze) {
         if (mWindowToken != null) {
             Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
             return;
         }
+        if (mFinished) {
+            Slog.w(TAG, "attach() called after dream already finished");
+            try {
+                mSandman.finishSelf(windowToken);
+            } catch (RemoteException ex) {
+                // system server died
+            }
+            return;
+        }
 
         if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
 
-        if (mSandman == null) {
-            loadSandman();
-        }
         mWindowToken = windowToken;
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
         mWindow.setFormat(PixelFormat.OPAQUE);
+        mCanDoze = canDoze;
 
         if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
                 windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -642,40 +772,25 @@
         mWindowManager = mWindow.getWindowManager();
 
         if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
-        try {
-            applySystemUiVisibilityFlags(
-                    (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
-                    View.SYSTEM_UI_FLAG_LOW_PROFILE);
-            getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed adding window view", t);
-            safelyFinish();
-            return;
-        }
+        applySystemUiVisibilityFlags(
+                (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+                View.SYSTEM_UI_FLAG_LOW_PROFILE);
+        getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
 
         // start it up
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                try {
-                    onDreamingStarted();
-                } catch (Throwable t) {
-                    Slog.w(TAG, "Crashed in onDreamingStarted()", t);
-                    safelyFinish();
-                }
+                if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+                onDreamingStarted();
             }
         });
     }
 
     private void safelyFinish() {
         if (mDebug) Slog.v(TAG, "safelyFinish()");
-        try {
-            finish();
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed in safelyFinish()", t);
-            finishInternal();
-            return;
-        }
+
+        finish();
 
         if (!mFinished) {
             Slog.w(TAG, "Bad dream, did not call super.finish()");
@@ -685,19 +800,21 @@
 
     private void finishInternal() {
         if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
-        if (mFinished) return;
-        try {
+
+        if (!mFinished) {
             mFinished = true;
 
-            if (mSandman != null) {
-                mSandman.finishSelf(mWindowToken);
+            if (mWindowToken == null) {
+                Slog.w(TAG, "Finish was called before the dream was attached.");
             } else {
-                Slog.w(TAG, "No dream manager found");
+                try {
+                    mSandman.finishSelf(mWindowToken);
+                } catch (RemoteException ex) {
+                    // system server died
+                }
             }
-            stopSelf(); // if launched via any other means
 
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed in finishInternal()", t);
+            stopSelf(); // if launched via any other means
         }
     }
 
@@ -732,32 +849,39 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        super.dump(fd, pw, args);
-
-        pw.print(TAG + ": ");
-        if (mWindowToken == null) {
-            pw.println("stopped");
-        } else {
-            pw.println("running (token=" + mWindowToken + ")");
-        }
-        pw.println("  window: " + mWindow);
-        pw.print("  flags:");
-        if (isInteractive()) pw.print(" interactive");
-        if (isLowProfile()) pw.print(" lowprofile");
-        if (isFullscreen()) pw.print(" fullscreen");
-        if (isScreenBright()) pw.print(" bright");
-        pw.println();
+        DumpUtils.dumpAsync(mHandler, new Dump() {
+            @Override
+            public void dump(PrintWriter pw) {
+                pw.print(TAG + ": ");
+                if (mWindowToken == null) {
+                    pw.println("stopped");
+                } else {
+                    pw.println("running (token=" + mWindowToken + ")");
+                }
+                pw.println("  window: " + mWindow);
+                pw.print("  flags:");
+                if (isInteractive()) pw.print(" interactive");
+                if (isLowProfile()) pw.print(" lowprofile");
+                if (isFullscreen()) pw.print(" fullscreen");
+                if (isScreenBright()) pw.print(" bright");
+                if (isDozing()) pw.print(" dozing");
+                pw.println();
+            }
+        }, pw, 1000);
     }
 
-    private class DreamServiceWrapper extends IDreamService.Stub {
-        public void attach(final IBinder windowToken) {
+    private final class DreamServiceWrapper extends IDreamService.Stub {
+        @Override
+        public void attach(final IBinder windowToken, final boolean canDoze) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    DreamService.this.attach(windowToken);
+                    DreamService.this.attach(windowToken, canDoze);
                 }
             });
         }
+
+        @Override
         public void detach() {
             mHandler.post(new Runnable() {
                 @Override
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/service/dreams/IDozeHardware.aidl
new file mode 100644
index 0000000..f5a657b
--- /dev/null
+++ b/core/java/android/service/dreams/IDozeHardware.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 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
+ */
+interface IDozeHardware {
+    byte[] sendMessage(String msg, in byte[] arg);
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c1b390..2718e316 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -16,10 +16,11 @@
 
 package android.service.dreams;
 
+import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
-import android.content.ComponentName;
 import android.os.IBinder;
+import android.service.dreams.IDozeHardware;
 
 /** @hide */
 interface IDreamManager {
@@ -31,4 +32,7 @@
     void testDream(in ComponentName componentName);
     boolean isDreaming();
     void finishSelf(in IBinder token);
+    void startDozing(in IBinder token);
+    void stopDozing(in IBinder token);
+    IDozeHardware getDozeHardware(in IBinder token);
 }
\ No newline at end of file
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 99dc0b7..bd58f1d 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -20,6 +20,6 @@
  * @hide
  */
 oneway interface IDreamService {
-    void attach(IBinder windowToken);
+    void attach(IBinder windowToken, boolean canDoze);
     void detach();
 }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c5a1b86c..74dda77 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -115,20 +115,6 @@
     public final static int ACTION_PASS_TO_USER = 0x00000001;
 
     /**
-     * This key event should wake the device.
-     * To be returned from {@link #interceptKeyBeforeQueueing}.
-     * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
-     */
-    public final static int ACTION_WAKE_UP = 0x00000002;
-
-    /**
-     * This key event should put the device to sleep (and engage keyguard if necessary)
-     * To be returned from {@link #interceptKeyBeforeQueueing}.
-     * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}.
-     */
-    public final static int ACTION_GO_TO_SLEEP = 0x00000004;
-
-    /**
      * Interface to the Window Manager state associated with a particular
      * window.  You can hold on to an instance of this interface from the call
      * to prepareAddWindow() until removeWindow().
@@ -751,8 +737,7 @@
      * @param policyFlags The policy flags associated with the key.
      * @param isScreenOn True if the screen is already on
      *
-     * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
-     *      {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+     * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
 
@@ -765,10 +750,9 @@
      * because it's the most fragile.
      * @param policyFlags The policy flags associated with the motion.
      *
-     * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
-     *      {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+     * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
 
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
index 194a084..e374563 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -49,9 +49,32 @@
      * Boot Phases
      */
     public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?
+
+    /**
+     * After receiving this boot phase, services can obtain lock settings data.
+     */
     public static final int PHASE_LOCK_SETTINGS_READY = 480;
+
+    /**
+     * After receiving this boot phase, services can safely call into core system services
+     * such as the PowerManager or PackageManager.
+     */
     public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+
+    /**
+     * After receiving this boot phase, services can broadcast Intents.
+     */
+    public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
+
+    /**
+     * After receiving this boot phase, services can start/bind to third party apps.
+     * Apps will be able to make Binder calls into services at this point.
+     */
     public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+
+    /**
+     * After receiving this boot phase, services must have finished all boot-related work.
+     */
     public static final int PHASE_BOOT_COMPLETE = 1000;
 
     private final Context mContext;
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
index 6c853be..eb8df0e 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -45,18 +45,13 @@
     }
 
     /**
-     * Starts a service by name if the class exists, otherwise ignores it.
+     * Starts a service by class name.
      *
-     * @return The service instance, or null if not found.
+     * @return The service instance.
      */
     @SuppressWarnings("unchecked")
-    public SystemService startServiceIfExists(String className) {
-        try {
-            return startService((Class<SystemService>)Class.forName(className));
-        } catch (ClassNotFoundException cnfe) {
-            Slog.i(TAG, className + " not available, ignoring.");
-            return null;
-        }
+    public SystemService startService(String className) throws ClassNotFoundException {
+        return startService((Class<SystemService>) Class.forName(className));
     }
 
     /**
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b34c792..559b11b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -652,6 +652,11 @@
          Must be in the range specified by minimum and maximum. -->
     <integer name="config_screenBrightnessSettingDefault">102</integer>
 
+    <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+         May be less than the minimum allowed brightness setting
+         that can be set by the user. -->
+    <integer name="config_screenBrightnessDoze">1</integer>
+
     <!-- Screen brightness used to dim the screen when the user activity
          timeout expires.  May be less than the minimum allowed brightness setting
          that can be set by the user. -->
@@ -1083,6 +1088,70 @@
     <!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
     <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
+    <!-- Are we allowed to dream while not plugged in? -->
+    <bool name="config_dreamsEnabledOnBattery">false</bool>
+    <!-- Minimum battery level to allow dreaming when powered.
+         Use -1 to disable this safety feature. -->
+    <integer name="config_dreamsBatteryLevelMinimumWhenPowered">-1</integer>
+    <!-- Minimum battery level to allow dreaming when not powered.
+         Use -1 to disable this safety feature. -->
+    <integer name="config_dreamsBatteryLevelMinimumWhenNotPowered">15</integer>
+    <!-- If the battery level drops by this percentage and the user activity timeout
+         has expired, then assume the device is receiving insufficient current to charge
+         effectively and terminate the dream.  Use -1 to disable this safety feature.  -->
+    <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
+
+    <!-- ComponentName of a dream to show whenever the system would otherwise have
+         gone to sleep.  When the PowerManager is asked to go to sleep, it will instead
+         try to start this dream if possible.  The dream should typically call startDozing()
+         to put the display into a low power state and allow the application processor
+         to be suspended.  When the dream ends, the system will go to sleep as usual.
+         Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an
+         empty string if none.
+
+         Note that doze dreams are not subject to the same start conditions as ordinary dreams.
+         Doze dreams will run whenever the power manager is in a dozing state. -->
+    <string name="config_dozeComponent"></string>
+
+    <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
+         device from the display on/off state.
+
+         When false, autosuspend_disable() will be called before the display is turned on
+         and autosuspend_enable() will be called after the display is turned off.
+         This mode provides best compatibility for devices using legacy power management
+         features such as early suspend / late resume.
+
+         When true, autosuspend_display() and autosuspend_enable() will be called
+         independently of whether the display is being turned on or off.  This mode
+         enables the power manager to suspend the application processor while the
+         display is on.
+
+         This resource should be set to "true" when a doze component has been specified
+         to maximize power savings but not all devices support it.
+
+         Refer to autosuspend.h for details.
+    -->
+    <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>
+
+    <!-- Power Management: Specifies whether to decouple the interactive state of the
+         device from the display on/off state.
+
+         When false, setInteractive(..., true) will be called before the display is turned on
+         and setInteractive(..., false) will be called after the display is turned off.
+         This mode provides best compatibility for devices that expect the interactive
+         state to be tied to the display state.
+
+         When true, setInteractive(...) will be called independently of whether the display
+         is being turned on or off.  This mode enables the power manager to reduce
+         clocks and disable the touch controller while the display is on.
+
+         This resource should be set to "true" when a doze component has been specified
+         to maximize power savings but not all devices support it.
+
+         Refer to power.h for details.
+    -->
+    <bool name="config_powerDecoupleInteractiveModeFromDisplay">false</bool>
+
     <!-- Base "touch slop" value used by ViewConfiguration as a
          movement threshold where scrolling should begin. -->
     <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6d90973..c38e753 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1504,6 +1504,7 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
+  <java-symbol type="integer" name="config_screenBrightnessDoze" />
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -1608,11 +1609,18 @@
   <java-symbol type="xml" name="storage_list" />
   <java-symbol type="bool" name="config_dreamsSupported" />
   <java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+  <java-symbol type="bool" name="config_dreamsEnabledOnBattery" />
   <java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
   <java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+  <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenPowered" />
+  <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenNotPowered" />
+  <java-symbol type="integer" name="config_dreamsBatteryLevelDrainCutoff" />
   <java-symbol type="string" name="config_dreamsDefaultComponent" />
+  <java-symbol type="string" name="config_dozeComponent" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
+  <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
+  <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index f09ef9f..506cf9d 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -880,13 +880,17 @@
     (closest) zoom level is 23.
       <p>Example: <code>"geo:47.6,-122.3?z=11"</code>
     </dd>
-  <dt><code>geo:0,0?q=lat,lng(label)</code></dt>
-    <dd>Show the map at the given longitude and latitude with a string label.
-      <p>Example: <code>"geo:0,0?q=34.99,-106.61(Treasure)"</code>
-    </dd>
+    <dt><code>geo:0,0?q=lat,lng(label)</code></dt>
+      <dd>Show the map at the given longitude and latitude with a string label.
+        <p>Example: <code>"geo:0,0?q=34.99,-106.61(Treasure)"</code>
+      </dd>
   <dt><code>geo:0,0?q=my+street+address</code></dt>
     <dd>Show the location for "my street address" (may be a specific address or location query).
-      <p>Example: <code>"geo:0,0?q=1600+amphitheatre+parkway+ca"</code>
+      <p>Example: <code>"geo:0,0?q=1600+Amphitheatre+Parkway%2C+CA"</code></p>
+      <p class="note"><strong>Note:</strong> All strings passed in the {@code geo} URI must
+      be encoded. For example, the string {@code 1st & Pike, Seattle} should become
+      {@code 1st%20%26%20Pike%2C%20Seattle}. Spaces in the string can be encoded with
+      {@code %20} or replaced with the plus sign ({@code +}).</p>
     </dd>
 </dl>
 </dd>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index f33ab40..76f29cd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3808,14 +3808,11 @@
         if (keyCode == KeyEvent.KEYCODE_POWER) {
             policyFlags |= WindowManagerPolicy.FLAG_WAKE;
         }
-        final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
-                | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
                     + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
-                    + " policyFlags=" + Integer.toHexString(policyFlags)
-                    + " isWakeKey=" + isWakeKey);
+                    + " policyFlags=" + Integer.toHexString(policyFlags));
         }
 
         if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3832,6 +3829,8 @@
         //        the device some other way (which is why we have an exemption here for injected
         //        events).
         int result;
+        boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
+                | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
         if (isScreenOn || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
@@ -3839,8 +3838,8 @@
             // When the screen is off and the key is not injected, determine whether
             // to wake the device but don't pass the key to the application.
             result = 0;
-            if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
-                result |= ACTION_WAKE_UP;
+            if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+                isWakeKey = false;
             }
         }
 
@@ -3950,7 +3949,8 @@
                         }
                         if ((mEndcallBehavior
                                 & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                            result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+                            mPowerManager.goToSleep(event.getEventTime());
+                            isWakeKey = false;
                         }
                     }
                 }
@@ -3994,7 +3994,8 @@
                     mPowerKeyTriggered = false;
                     cancelPendingScreenshotChordAction();
                     if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
-                        result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+                        mPowerManager.goToSleep(event.getEventTime());
+                        isWakeKey = false;
                     }
                     mPendingPowerKeyUpCanceled = false;
                 }
@@ -4064,6 +4065,10 @@
                 break;
             }
         }
+
+        if (isWakeKey) {
+            mPowerManager.wakeUp(event.getEventTime());
+        }
         return result;
     }
 
@@ -4104,13 +4109,13 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
+    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
         int result = 0;
 
         final boolean isWakeMotion = (policyFlags
                 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
         if (isWakeMotion) {
-            result |= ACTION_WAKE_UP;
+            mPowerManager.wakeUp(whenNanos / 1000000);
         }
         return result;
     }
diff --git a/services/Android.mk b/services/Android.mk
index a8881b6..5260540 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -8,13 +8,23 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under,java)
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    services.core \
-    services.accessibility \
-    services.appwidget \
-    services.backup \
-    services.devicepolicy \
-    services.print
+# Uncomment to enable output of certain warnings (deprecated, unchecked)
+# LOCAL_JAVACFLAGS := -Xlint
+
+# Services that will be built as part of services.jar
+# These should map to directory names relative to this
+# Android.mk.
+services := \
+    core \
+    accessibility \
+    appwidget \
+    backup \
+    devicepolicy \
+    print \
+    usb
+
+# The convention is to name each service module 'services.$(module_name)'
+LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
 
 include $(BUILD_JAVA_LIBRARY)
 
@@ -39,7 +49,16 @@
 
 include $(BUILD_SHARED_LIBRARY)
 
+# =============================================================
+
 ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call all-makefiles-under, $(LOCAL_PATH))
+# A full make is happening, so make everything.
+include $(call all-makefiles-under,$(LOCAL_PATH))
+else
+# If we ran an mm[m] command, we still want to build the individual
+# services that we depend on. This differs from the above condition
+# by only including service makefiles and not any tests or other
+# modules.
+include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services))
 endif
 
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 85ef33e..649b5c9 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -85,6 +85,7 @@
             pw.println("    mToken=" + mCurrentDream.mToken);
             pw.println("    mName=" + mCurrentDream.mName);
             pw.println("    mIsTest=" + mCurrentDream.mIsTest);
+            pw.println("    mCanDoze=" + mCurrentDream.mCanDoze);
             pw.println("    mUserId=" + mCurrentDream.mUserId);
             pw.println("    mBound=" + mCurrentDream.mBound);
             pw.println("    mService=" + mCurrentDream.mService);
@@ -94,15 +95,18 @@
         }
     }
 
-    public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+    public void startDream(Binder token, ComponentName name,
+            boolean isTest, boolean canDoze, int userId) {
         stopDream();
 
         // Close the notification shade. Don't need to send to all, but better to be explicit.
         mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
 
-        Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+        Slog.i(TAG, "Starting dream: name=" + name
+                + ", isTest=" + isTest + ", canDoze=" + canDoze
+                + ", userId=" + userId);
 
-        mCurrentDream = new DreamRecord(token, name, isTest, userId);
+        mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
 
         try {
             mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -140,7 +144,8 @@
         final DreamRecord oldDream = mCurrentDream;
         mCurrentDream = null;
         Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
-                + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+                + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+                + ", userId=" + oldDream.mUserId);
 
         mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
 
@@ -187,7 +192,7 @@
     private void attach(IDreamService service) {
         try {
             service.asBinder().linkToDeath(mCurrentDream, 0);
-            service.attach(mCurrentDream.mToken);
+            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
         } catch (RemoteException ex) {
             Slog.e(TAG, "The dream service died unexpectedly.", ex);
             stopDream();
@@ -213,6 +218,7 @@
         public final Binder mToken;
         public final ComponentName mName;
         public final boolean mIsTest;
+        public final boolean mCanDoze;
         public final int mUserId;
 
         public boolean mBound;
@@ -221,10 +227,11 @@
         public boolean mSentStartBroadcast;
 
         public DreamRecord(Binder token, ComponentName name,
-                boolean isTest, int userId) {
+                boolean isTest, boolean canDoze, int userId) {
             mToken = token;
             mName = name;
             mIsTest = isTest;
+            mCanDoze = canDoze;
             mUserId  = userId;
         }
 
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index ffb113c..fd2f8a1 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -30,16 +30,20 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.DreamManagerInternal;
 import android.service.dreams.DreamService;
+import android.service.dreams.IDozeHardware;
 import android.service.dreams.IDreamManager;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import java.io.FileDescriptor;
@@ -64,11 +68,16 @@
     private final DreamHandler mHandler;
     private final DreamController mController;
     private final PowerManager mPowerManager;
+    private final PowerManager.WakeLock mDozeWakeLock;
+    private final McuHal mMcuHal; // synchronized on self
 
     private Binder mCurrentDreamToken;
     private ComponentName mCurrentDreamName;
     private int mCurrentDreamUserId;
     private boolean mCurrentDreamIsTest;
+    private boolean mCurrentDreamCanDoze;
+    private boolean mCurrentDreamIsDozing;
+    private DozeHardwareWrapper mCurrentDreamDozeHardware;
 
     public DreamManagerService(Context context) {
         super(context);
@@ -77,6 +86,12 @@
         mController = new DreamController(context, mHandler, mControllerListener);
 
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
+
+        mMcuHal = McuHal.open();
+        if (mMcuHal != null) {
+            mMcuHal.reset();
+        }
     }
 
     @Override
@@ -103,10 +118,15 @@
         pw.println("DREAM MANAGER (dumpsys dreams)");
         pw.println();
 
+        pw.println("mMcuHal=" + mMcuHal);
+        pw.println();
         pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
         pw.println("mCurrentDreamName=" + mCurrentDreamName);
         pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
         pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+        pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
+        pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
+        pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
         pw.println();
 
         DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
@@ -163,16 +183,16 @@
 
     private void testDreamInternal(ComponentName dream, int userId) {
         synchronized (mLock) {
-            startDreamLocked(dream, true /*isTest*/, userId);
+            startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
         }
     }
 
-    private void startDreamInternal() {
-        int userId = ActivityManager.getCurrentUser();
-        ComponentName dream = chooseDreamForUser(userId);
+    private void startDreamInternal(boolean doze) {
+        final int userId = ActivityManager.getCurrentUser();
+        final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId);
         if (dream != null) {
             synchronized (mLock) {
-                startDreamLocked(dream, false /*isTest*/, userId);
+                startDreamLocked(dream, false /*isTest*/, doze, userId);
             }
         }
     }
@@ -183,6 +203,44 @@
         }
     }
 
+    private void startDozingInternal(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "Dream requested to start dozing: " + token);
+        }
+
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+                    && !mCurrentDreamIsDozing) {
+                mCurrentDreamIsDozing = true;
+                mDozeWakeLock.acquire();
+            }
+        }
+    }
+
+    private void stopDozingInternal(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "Dream requested to stop dozing: " + token);
+        }
+
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
+                mCurrentDreamIsDozing = false;
+                mDozeWakeLock.release();
+            }
+        }
+    }
+
+    private IDozeHardware getDozeHardwareInternal(IBinder token) {
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+                    && mCurrentDreamDozeHardware == null && mMcuHal != null) {
+                mCurrentDreamDozeHardware = new DozeHardwareWrapper();
+                return mCurrentDreamDozeHardware;
+            }
+            return null;
+        }
+    }
+
     private ComponentName chooseDreamForUser(int userId) {
         ComponentName[] dreams = getDreamComponentsForUser(userId);
         return dreams != null && dreams.length != 0 ? dreams[0] : null;
@@ -231,6 +289,20 @@
         return name == null ? null : ComponentName.unflattenFromString(name);
     }
 
+    private ComponentName getDozeComponent() {
+        // Read the component from a system property to facilitate debugging.
+        // Note that for production devices, the dream should actually be declared in
+        // a config.xml resource.
+        String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
+        if (TextUtils.isEmpty(name)) {
+            // Read the component from a config.xml resource.
+            // The value should be specified in a resource overlay for the product.
+            name = mContext.getResources().getString(
+                    com.android.internal.R.string.config_dozeComponent);
+        }
+        return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name);
+    }
+
     private boolean serviceExists(ComponentName name) {
         try {
             return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
@@ -240,9 +312,10 @@
     }
 
     private void startDreamLocked(final ComponentName name,
-            final boolean isTest, final int userId) {
+            final boolean isTest, final boolean canDoze, final int userId) {
         if (Objects.equal(mCurrentDreamName, name)
                 && mCurrentDreamIsTest == isTest
+                && mCurrentDreamCanDoze == canDoze
                 && mCurrentDreamUserId == userId) {
             return;
         }
@@ -255,12 +328,13 @@
         mCurrentDreamToken = newToken;
         mCurrentDreamName = name;
         mCurrentDreamIsTest = isTest;
+        mCurrentDreamCanDoze = canDoze;
         mCurrentDreamUserId = userId;
 
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                mController.startDream(newToken, name, isTest, userId);
+                mController.startDream(newToken, name, isTest, canDoze, userId);
             }
         });
     }
@@ -284,7 +358,16 @@
         mCurrentDreamToken = null;
         mCurrentDreamName = null;
         mCurrentDreamIsTest = false;
+        mCurrentDreamCanDoze = false;
         mCurrentDreamUserId = 0;
+        if (mCurrentDreamIsDozing) {
+            mCurrentDreamIsDozing = false;
+            mDozeWakeLock.release();
+        }
+        if (mCurrentDreamDozeHardware != null) {
+            mCurrentDreamDozeHardware.release();
+            mCurrentDreamDozeHardware = null;
+        }
     }
 
     private void checkPermission(String permission) {
@@ -473,12 +556,57 @@
                 Binder.restoreCallingIdentity(ident);
             }
         }
+
+        @Override // Binder call
+        public void startDozing(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                startDozingInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void stopDozing(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                stopDozingInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public IDozeHardware getDozeHardware(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getDozeHardwareInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     private final class LocalService extends DreamManagerInternal {
         @Override
-        public void startDream() {
-            startDreamInternal();
+        public void startDream(boolean doze) {
+            startDreamInternal(doze);
         }
 
         @Override
@@ -491,4 +619,37 @@
             return isDreamingInternal();
         }
     }
+
+    private final class DozeHardwareWrapper extends IDozeHardware.Stub {
+        private boolean mReleased;
+
+        public void release() {
+            synchronized (mMcuHal) {
+                if (!mReleased) {
+                    mReleased = true;
+                    mMcuHal.reset();
+                }
+            }
+        }
+
+        @Override // Binder call
+        public byte[] sendMessage(String msg, byte[] arg) {
+            if (msg == null) {
+                throw new IllegalArgumentException("msg must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mMcuHal) {
+                    if (mReleased) {
+                        throw new IllegalStateException("This operation cannot be performed "
+                                + "because the dream has ended.");
+                    }
+                    return mMcuHal.sendMessage(msg, arg);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java
new file mode 100644
index 0000000..1dc79c7
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/McuHal.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 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 com.android.server.dreams;
+
+import android.service.dreams.DozeHardware;
+
+/**
+ * Provides access to the low-level microcontroller hardware abstraction layer.
+ */
+final class McuHal {
+    private final long mPtr;
+
+    private static native long nativeOpen();
+    private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg);
+
+    private McuHal(long ptr) {
+        mPtr = ptr;
+    }
+
+    public static McuHal open() {
+        long ptr = nativeOpen();
+        return ptr != 0 ? new McuHal(ptr) : null;
+    }
+
+    public void reset() {
+        sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF);
+    }
+
+    public byte[] sendMessage(String msg, byte[] arg) {
+        return nativeSendMessage(mPtr, msg, arg);
+    }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 69281bc..73033e0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1329,8 +1329,9 @@
     }
 
     // Native callback.
-    private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
-        return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+    private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+        return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+                whenNanos, policyFlags);
     }
 
     // Native callback.
@@ -1491,7 +1492,7 @@
 
         public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
 
-        public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+        public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
 
         public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                 KeyEvent event, int policyFlags);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index df83fd7..da0c38d 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2546,15 +2546,41 @@
         }
     }
 
+    /**
+     * Compares two sets of signatures. Returns:
+     * <br />
+     * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
+     * <br />
+     * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
+     * <br />
+     * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
+     * <br />
+     * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
+     * <br />
+     * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
+     */
     static int compareSignatures(Signature[] s1, Signature[] s2) {
         if (s1 == null) {
             return s2 == null
                     ? PackageManager.SIGNATURE_NEITHER_SIGNED
                     : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
         }
+
         if (s2 == null) {
             return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
         }
+
+        if (s1.length != s2.length) {
+            return PackageManager.SIGNATURE_NO_MATCH;
+        }
+
+        // Since both signature sets are of size 1, we can compare without HashSets.
+        if (s1.length == 1) {
+            return s1[0].equals(s2[0]) ?
+                    PackageManager.SIGNATURE_MATCH :
+                    PackageManager.SIGNATURE_NO_MATCH;
+        }
+
         HashSet<Signature> set1 = new HashSet<Signature>();
         for (Signature sig : s1) {
             set1.add(sig);
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index f1be504..bd9acb9 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -193,6 +193,9 @@
     // The light sensor, or null if not available or needed.
     private Sensor mLightSensor;
 
+    // The doze screen brightness.
+    private final int mScreenBrightnessDozeConfig;
+
     // The dim screen brightness.
     private final int mScreenBrightnessDimConfig;
 
@@ -364,6 +367,9 @@
 
         final Resources resources = context.getResources();
 
+        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessDoze));
+
         mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
                 com.android.internal.R.integer.config_screenBrightnessDim));
 
@@ -559,7 +565,7 @@
         final boolean mustNotify;
         boolean mustInitialize = false;
         boolean updateAutoBrightness = mTwilightChanged;
-        boolean wasDim = false;
+        boolean wasDimOrDoze = false;
         mTwilightChanged = false;
 
         synchronized (mLock) {
@@ -579,7 +585,8 @@
                         != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
                     updateAutoBrightness = true;
                 }
-                wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
+                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
+                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
                 mPowerRequest.copyFrom(mPendingRequestLocked);
                 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
                 mPendingWaitForNegativeProximityLocked = false;
@@ -626,12 +633,12 @@
 
         // Turn on the light sensor if needed.
         if (mLightSensor != null) {
-            setLightSensorEnabled(mPowerRequest.useAutoBrightness
-                    && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
+            setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(),
+                    updateAutoBrightness);
         }
 
         // Set the screen brightness.
-        if (wantScreenOn(mPowerRequest.screenState)) {
+        if (mPowerRequest.wantScreenOnAny()) {
             int target;
             boolean slow;
             if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
@@ -648,12 +655,16 @@
                 slow = false;
                 mUsingScreenAutoBrightness = false;
             }
-            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
+                // Dim quickly to the doze state.
+                target = mScreenBrightnessDozeConfig;
+                slow = false;
+            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
                 // Dim quickly by at least some minimum amount.
                 target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
                         mScreenBrightnessDimConfig);
                 slow = false;
-            } else if (wasDim) {
+            } else if (wasDimOrDoze) {
                 // Brighten quickly.
                 slow = false;
             }
@@ -666,7 +677,7 @@
 
         // Animate the screen on or off.
         if (!mScreenOffBecauseOfProximity) {
-            if (wantScreenOn(mPowerRequest.screenState)) {
+            if (mPowerRequest.wantScreenOnAny()) {
                 // Want screen on.
                 // Wait for previous off animation to complete beforehand.
                 // It is relatively short but if we cancel it and switch to the
@@ -1211,6 +1222,7 @@
 
         pw.println();
         pw.println("Display Controller Configuration:");
+        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
         pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
         pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
@@ -1288,15 +1300,6 @@
         }
     }
 
-    private static boolean wantScreenOn(int state) {
-        switch (state) {
-            case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
-            case DisplayPowerRequest.SCREEN_STATE_DIM:
-                return true;
-        }
-        return false;
-    }
-
     /**
      * Asynchronous callbacks from the power controller to the power manager service.
      */
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequest.java b/services/core/java/com/android/server/power/DisplayPowerRequest.java
index 22f17d7..6061a40 100644
--- a/services/core/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/core/java/com/android/server/power/DisplayPowerRequest.java
@@ -30,10 +30,11 @@
  */
 final class DisplayPowerRequest {
     public static final int SCREEN_STATE_OFF = 0;
-    public static final int SCREEN_STATE_DIM = 1;
-    public static final int SCREEN_STATE_BRIGHT = 2;
+    public static final int SCREEN_STATE_DOZE = 1;
+    public static final int SCREEN_STATE_DIM = 2;
+    public static final int SCREEN_STATE_BRIGHT = 3;
 
-    // The requested minimum screen power state: off, dim or bright.
+    // The requested minimum screen power state: off, doze, dim or bright.
     public int screenState;
 
     // If true, the proximity sensor overrides the screen state when an object is
@@ -75,6 +76,23 @@
         copyFrom(other);
     }
 
+    // Returns true if we want the screen on in any mode, including doze.
+    public boolean wantScreenOnAny() {
+        return screenState != SCREEN_STATE_OFF;
+    }
+
+    // Returns true if we want the screen on in a normal mode, excluding doze.
+    // This is usually what we want to tell the rest of the system.  For compatibility
+    // reasons, we pretend the screen is off when dozing.
+    public boolean wantScreenOnNormal() {
+        return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
+    }
+
+    public boolean wantLightSensorEnabled() {
+        // Specifically, we don't want the light sensor while dozing.
+        return useAutoBrightness && wantScreenOnNormal();
+    }
+
     public void copyFrom(DisplayPowerRequest other) {
         screenState = other.screenState;
         useProximitySensor = other.useProximitySensor;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3dec234..16b09bc 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -83,7 +83,7 @@
 
     // Message: Sent when a user activity timeout occurs to update the power state.
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
-    // Message: Sent when the device enters or exits a napping or dreaming state.
+    // Message: Sent when the device enters or exits a dreaming or dozing state.
     private static final int MSG_SANDMAN = 2;
     // Message: Sent when the screen on blocker is released.
     private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
@@ -117,19 +117,21 @@
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
+    // The device typically passes through the dozing state first.
     private static final int WAKEFULNESS_ASLEEP = 0;
     // Wakefulness: The device is fully awake.  It can be put to sleep by a call to goToSleep().
-    // When the user activity timeout expires, the device may start napping or go to sleep.
+    // When the user activity timeout expires, the device may start dreaming or go to sleep.
     private static final int WAKEFULNESS_AWAKE = 1;
-    // Wakefulness: The device is napping.  It is deciding whether to dream or go to sleep
-    // but hasn't gotten around to it yet.  It can be awoken by a call to wakeUp(), which
-    // ends the nap. User activity may brighten the screen but does not end the nap.
-    private static final int WAKEFULNESS_NAPPING = 2;
     // Wakefulness: The device is dreaming.  It can be awoken by a call to wakeUp(),
     // which ends the dream.  The device goes to sleep when goToSleep() is called, when
     // the dream ends or when unplugged.
     // User activity may brighten the screen but does not end the dream.
-    private static final int WAKEFULNESS_DREAMING = 3;
+    private static final int WAKEFULNESS_DREAMING = 2;
+    // Wakefulness: The device is dozing.  It is almost asleep but is allowing a special
+    // low-power "doze" dream to run which keeps the display on but lets the application
+    // processor be suspended.  It can be awoken by a call to wakeUp() which ends the dream.
+    // The device fully goes to sleep if the dream cannot be started or ends on its own.
+    private static final int WAKEFULNESS_DOZING = 3;
 
     // Summarizes the state of all active wakelocks.
     private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -138,6 +140,7 @@
     private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
     private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
+    private static final int WAKE_LOCK_DOZE = 1 << 6;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -164,11 +167,6 @@
     // Poll interval in milliseconds for watching boot animation finished.
     private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
 
-    // If the battery level drops by this percentage and the user activity timeout
-    // has expired, then assume the device is receiving insufficient current to charge
-    // effectively and terminate the dream.
-    private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
-
     private final Context mContext;
     private LightsManager mLightsManager;
     private BatteryService mBatteryService;
@@ -195,6 +193,10 @@
     // This is distinct from the screen power state, which is managed separately.
     private int mWakefulness;
 
+    // True if the sandman has just been summoned for the first time since entering the
+    // dreaming or dozing state.  Indicates whether a new dream should begin.
+    private boolean mSandmanSummoned;
+
     // True if MSG_SANDMAN has been scheduled.
     private boolean mSandmanScheduled;
 
@@ -265,6 +267,14 @@
     // True if boot completed occurred.  We keep the screen on until this happens.
     private boolean mBootCompleted;
 
+    // True if auto-suspend mode is enabled.
+    // Refer to autosuspend.h.
+    private boolean mAutoSuspendModeEnabled;
+
+    // True if interactive mode is enabled.
+    // Refer to power.h.
+    private boolean mInteractiveModeEnabled;
+
     // True if the device is plugged into a power source.
     private boolean mIsPowered;
 
@@ -282,6 +292,12 @@
     // The current dock state.
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
+    // True to decouple auto-suspend mode from the display state.
+    private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+
+    // True to decouple interactive mode from the display state.
+    private boolean mDecoupleInteractiveModeFromDisplayConfig;
+
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
 
@@ -300,6 +316,22 @@
     // Default value for dreams activate-on-dock
     private boolean mDreamsActivatedOnDockByDefaultConfig;
 
+    // True if dreams can run while not plugged in.
+    private boolean mDreamsEnabledOnBatteryConfig;
+
+    // Minimum battery level to allow dreaming when powered.
+    // Use -1 to disable this safety feature.
+    private int mDreamsBatteryLevelMinimumWhenPoweredConfig;
+
+    // Minimum battery level to allow dreaming when not powered.
+    // Use -1 to disable this safety feature.
+    private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig;
+
+    // If the battery level drops by this percentage and the user activity timeout
+    // has expired, then assume the device is receiving insufficient current to charge
+    // effectively and terminate the dream.  Use -1 to disable this safety feature.
+    private int mDreamsBatteryLevelDrainCutoffConfig;
+
     // True if dreams are enabled by the user.
     private boolean mDreamsEnabledSetting;
 
@@ -523,6 +555,10 @@
     private void readConfigurationLocked() {
         final Resources resources = mContext.getResources();
 
+        mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
+        mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
         mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
@@ -535,6 +571,14 @@
                 com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
         mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+        mDreamsEnabledOnBatteryConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_dreamsEnabledOnBattery);
+        mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
+                com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered);
+        mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
+                com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
+        mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
+                com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
     }
 
     private void updateSettingsLocked() {
@@ -762,6 +806,7 @@
                 case PowerManager.SCREEN_DIM_WAKE_LOCK:
                 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                 case PowerManager.FULL_WAKE_LOCK:
+                case PowerManager.DOZE_WAKE_LOCK:
                     return true;
 
                 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
@@ -794,7 +839,8 @@
         }
 
         if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
-                || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) {
+                || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
+                || !mBootCompleted || !mSystemReady) {
             return false;
         }
 
@@ -843,18 +889,21 @@
         switch (mWakefulness) {
             case WAKEFULNESS_ASLEEP:
                 Slog.i(TAG, "Waking up from sleep...");
-                sendPendingNotificationsLocked();
-                mNotifier.onWakeUpStarted();
-                mSendWakeUpFinishedNotificationWhenReady = true;
                 break;
             case WAKEFULNESS_DREAMING:
                 Slog.i(TAG, "Waking up from dream...");
                 break;
-            case WAKEFULNESS_NAPPING:
-                Slog.i(TAG, "Waking up from nap...");
+            case WAKEFULNESS_DOZING:
+                Slog.i(TAG, "Waking up from dozing...");
                 break;
         }
 
+        if (mWakefulness != WAKEFULNESS_DREAMING) {
+            sendPendingNotificationsLocked();
+            mNotifier.onWakeUpStarted();
+            mSendWakeUpFinishedNotificationWhenReady = true;
+        }
+
         mLastWakeTime = eventTime;
         mWakefulness = WAKEFULNESS_AWAKE;
         mDirty |= DIRTY_WAKEFULNESS;
@@ -877,13 +926,17 @@
         }
     }
 
+    // This method is called goToSleep for historical reasons but we actually start
+    // dozing before really going to sleep.
     @SuppressWarnings("deprecation")
     private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
         }
 
-        if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+        if (eventTime < mLastWakeTime
+                || mWakefulness == WAKEFULNESS_ASLEEP
+                || mWakefulness == WAKEFULNESS_DOZING
                 || !mBootCompleted || !mSystemReady) {
             return false;
         }
@@ -907,7 +960,8 @@
 
         mLastSleepTime = eventTime;
         mDirty |= DIRTY_WAKEFULNESS;
-        mWakefulness = WAKEFULNESS_ASLEEP;
+        mWakefulness = WAKEFULNESS_DOZING;
+        mSandmanSummoned = true;
 
         // Report the number of wake locks that will be cleared by going to sleep.
         int numWakeLocksCleared = 0;
@@ -947,7 +1001,26 @@
         Slog.i(TAG, "Nap time...");
 
         mDirty |= DIRTY_WAKEFULNESS;
-        mWakefulness = WAKEFULNESS_NAPPING;
+        mWakefulness = WAKEFULNESS_DREAMING;
+        mSandmanSummoned = true;
+        return true;
+    }
+
+    // Done dozing, drop everything and go to sleep.
+    private boolean reallyGoToSleepNoUpdateLocked(long eventTime) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime);
+        }
+
+        if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+                || !mBootCompleted || !mSystemReady) {
+            return false;
+        }
+
+        Slog.i(TAG, "Sleeping...");
+
+        mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_ASLEEP;
         return true;
     }
 
@@ -1023,7 +1096,7 @@
             mPlugType = mBatteryService.getPlugType();
             mBatteryLevel = mBatteryService.getBatteryLevel();
 
-            if (DEBUG) {
+            if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
                         + ", mIsPowered=" + mIsPowered
                         + ", oldPlugType=" + oldPlugType
@@ -1083,8 +1156,7 @@
         }
 
         // If already dreaming and becoming powered, then don't wake.
-        if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
-                || mWakefulness == WAKEFULNESS_DREAMING)) {
+        if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
             return false;
         }
 
@@ -1131,35 +1203,45 @@
                         mWakeLockSummary |= WAKE_LOCK_CPU;
                         break;
                     case PowerManager.FULL_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                        if (mWakefulness == WAKEFULNESS_AWAKE
+                                || mWakefulness == WAKEFULNESS_DREAMING) {
                             mWakeLockSummary |= WAKE_LOCK_CPU
                                     | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
-                            if (mWakefulness == WAKEFULNESS_AWAKE) {
-                                mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                            }
+                        }
+                        if (mWakefulness == WAKEFULNESS_AWAKE) {
+                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
                         }
                         break;
                     case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                        if (mWakefulness == WAKEFULNESS_AWAKE
+                                || mWakefulness == WAKEFULNESS_DREAMING) {
                             mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
-                            if (mWakefulness == WAKEFULNESS_AWAKE) {
-                                mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                            }
+                        }
+                        if (mWakefulness == WAKEFULNESS_AWAKE) {
+                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
                         }
                         break;
                     case PowerManager.SCREEN_DIM_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                        if (mWakefulness == WAKEFULNESS_AWAKE
+                                || mWakefulness == WAKEFULNESS_DREAMING) {
                             mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
-                            if (mWakefulness == WAKEFULNESS_AWAKE) {
-                                mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                            }
+                        }
+                        if (mWakefulness == WAKEFULNESS_AWAKE) {
+                            mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
                         }
                         break;
                     case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                        if (mWakefulness == WAKEFULNESS_AWAKE
+                                || mWakefulness == WAKEFULNESS_DREAMING
+                                || mWakefulness == WAKEFULNESS_DOZING) {
                             mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                         }
                         break;
+                    case PowerManager.DOZE_WAKE_LOCK:
+                        if (mWakefulness == WAKEFULNESS_DOZING) {
+                            mWakeLockSummary |= WAKE_LOCK_DOZE;
+                        }
+                        break;
                 }
             }
 
@@ -1184,7 +1266,8 @@
             mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
 
             long nextTimeout = 0;
-            if (mWakefulness != WAKEFULNESS_ASLEEP) {
+            if (mWakefulness == WAKEFULNESS_AWAKE
+                    || mWakefulness == WAKEFULNESS_DREAMING) {
                 final int screenOffTimeout = getScreenOffTimeoutLocked();
                 final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
 
@@ -1205,8 +1288,7 @@
                         && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                     nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                     if (now < nextTimeout
-                            && mDisplayPowerRequest.screenState
-                                    != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                            && mDisplayPowerRequest.wantScreenOnNormal()) {
                         mUserActivitySummary = mDisplayPowerRequest.screenState
                                 == DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
                                 USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
@@ -1268,7 +1350,7 @@
     /**
      * Updates the wakefulness of the device.
      *
-     * This is the function that decides whether the device should start napping
+     * This is the function that decides whether the device should start dreaming
      * based on the current wake locks and user activity state.  It may modify mDirty
      * if the wakefulness changes.
      *
@@ -1357,7 +1439,7 @@
     }
 
     /**
-     * Called when the device enters or exits a napping or dreaming state.
+     * Called when the device enters or exits a dreaming or dozing state.
      *
      * We do this asynchronously because we must call out of the power manager to start
      * the dream and we don't want to hold our lock while doing so.  There is a risk that
@@ -1365,46 +1447,60 @@
      */
     private void handleSandman() { // runs on handler thread
         // Handle preconditions.
-        boolean startDreaming = false;
+        final boolean startDreaming;
+        final int wakefulness;
         synchronized (mLock) {
             mSandmanScheduled = false;
-            boolean canDream = canDreamLocked();
-            if (DEBUG_SPEW) {
-                Slog.d(TAG, "handleSandman: canDream=" + canDream
-                        + ", mWakefulness=" + wakefulnessToString(mWakefulness));
-            }
-
-            if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
-                startDreaming = true;
+            wakefulness = mWakefulness;
+            if (mSandmanSummoned) {
+                startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked())
+                        || wakefulness == WAKEFULNESS_DOZING);
+                mSandmanSummoned = false;
+            } else {
+                startDreaming = false;
             }
         }
 
         // Start dreaming if needed.
         // We only control the dream on the handler thread, so we don't need to worry about
         // concurrent attempts to start or stop the dream.
-        boolean isDreaming = false;
+        final boolean isDreaming;
         if (mDreamManager != null) {
+            // Restart the dream whenever the sandman is summoned.
             if (startDreaming) {
-                mDreamManager.startDream();
+                mDreamManager.stopDream();
+                mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
             }
             isDreaming = mDreamManager.isDreaming();
+        } else {
+            isDreaming = false;
         }
 
         // Update dream state.
-        // We might need to stop the dream again if the preconditions changed.
-        boolean continueDreaming = false;
         synchronized (mLock) {
-            if (isDreaming && canDreamLocked()) {
-                if (mWakefulness == WAKEFULNESS_NAPPING) {
-                    mWakefulness = WAKEFULNESS_DREAMING;
-                    mDirty |= DIRTY_WAKEFULNESS;
-                    mBatteryLevelWhenDreamStarted = mBatteryLevel;
-                    updatePowerStateLocked();
-                    continueDreaming = true;
-                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
-                    if (!isBeingKeptAwakeLocked()
+            // Remember the initial battery level when the dream started.
+            if (startDreaming && isDreaming) {
+                mBatteryLevelWhenDreamStarted = mBatteryLevel;
+                if (wakefulness == WAKEFULNESS_DOZING) {
+                    Slog.i(TAG, "Dozing...");
+                } else {
+                    Slog.i(TAG, "Dreaming...");
+                }
+            }
+
+            // If preconditions changed, wait for the next iteration to determine
+            // whether the dream should continue (or be restarted).
+            if (mSandmanSummoned || mWakefulness != wakefulness) {
+                return; // wait for next cycle
+            }
+
+            // Determine whether the dream should continue.
+            if (wakefulness == WAKEFULNESS_DREAMING) {
+                if (isDreaming && canDreamLocked()) {
+                    if (mDreamsBatteryLevelDrainCutoffConfig >= 0
                             && mBatteryLevel < mBatteryLevelWhenDreamStarted
-                                    - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) {
+                                    - mDreamsBatteryLevelDrainCutoffConfig
+                            && !isBeingKeptAwakeLocked()) {
                         // If the user activity timeout expired and the battery appears
                         // to be draining faster than it is charging then stop dreaming
                         // and go to sleep.
@@ -1414,53 +1510,64 @@
                                 + mBatteryLevelWhenDreamStarted + "%.  "
                                 + "Battery level now: " + mBatteryLevel + "%.");
                     } else {
-                        continueDreaming = true;
+                        return; // continue dreaming
                     }
                 }
-            }
-            if (!continueDreaming) {
-                handleDreamFinishedLocked();
+
+                // Dream has ended or will be stopped.  Update the power state.
+                if (isItBedTimeYetLocked()) {
+                    goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
+                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+                    updatePowerStateLocked();
+                } else {
+                    wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
+                    updatePowerStateLocked();
+                }
+            } else if (wakefulness == WAKEFULNESS_DOZING) {
+                if (isDreaming) {
+                    return; // continue dozing
+                }
+
+                // Doze has ended or will be stopped.  Update the power state.
+                reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis());
+                updatePowerStateLocked();
             }
         }
 
-        // Stop dreaming if needed.
-        // It's possible that something else changed to make us need to start the dream again.
-        // If so, then the power manager will have posted another message to the handler
-        // to take care of it later.
-        if (mDreamManager != null) {
-            if (!continueDreaming) {
-                mDreamManager.stopDream();
-            }
+        // Stop dream.
+        if (isDreaming) {
+            mDreamManager.stopDream();
         }
     }
 
     /**
-     * Returns true if the device is allowed to dream in its current state
-     * assuming that it is currently napping or dreaming.
+     * Returns true if the device is allowed to dream in its current state.
+     * This function is not called when dozing.
      */
     private boolean canDreamLocked() {
-        return mDreamsSupportedConfig
-                && mDreamsEnabledSetting
-                && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
-                && mBootCompleted
-                && (mIsPowered || isBeingKeptAwakeLocked());
-    }
-
-    /**
-     * Called when a dream is ending to figure out what to do next.
-     */
-    private void handleDreamFinishedLocked() {
-        if (mWakefulness == WAKEFULNESS_NAPPING
-                || mWakefulness == WAKEFULNESS_DREAMING) {
-            if (isItBedTimeYetLocked()) {
-                goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
-                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
-                updatePowerStateLocked();
-            } else {
-                wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
-                updatePowerStateLocked();
+        if (mWakefulness != WAKEFULNESS_DREAMING
+                || !mDreamsSupportedConfig
+                || !mDreamsEnabledSetting
+                || !mDisplayPowerRequest.wantScreenOnNormal()
+                || !mBootCompleted) {
+            return false;
+        }
+        if (!isBeingKeptAwakeLocked()) {
+            if (!mIsPowered && !mDreamsEnabledByDefaultConfig) {
+                return false;
+            }
+            if (!mIsPowered
+                    && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
+                    && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
+                return false;
+            }
+            if (mIsPowered
+                    && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
+                    && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
+                return false;
             }
         }
+        return true;
     }
 
     private void handleScreenOnBlockerReleased() {
@@ -1482,11 +1589,11 @@
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                 | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
-            int newScreenState = getDesiredScreenPowerStateLocked();
+            final int newScreenState = getDesiredScreenPowerStateLocked();
             if (newScreenState != mDisplayPowerRequest.screenState) {
                 mDisplayPowerRequest.screenState = newScreenState;
                 nativeSetPowerState(
-                        newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF,
+                        mDisplayPowerRequest.wantScreenOnNormal(),
                         newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
             }
 
@@ -1555,6 +1662,10 @@
             return DisplayPowerRequest.SCREEN_STATE_OFF;
         }
 
+        if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+            return DisplayPowerRequest.SCREEN_STATE_DOZE;
+        }
+
         if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                 || !mBootCompleted) {
@@ -1606,7 +1717,18 @@
      */
     private void updateSuspendBlockerLocked() {
         final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
-        final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
+        final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
+        final boolean autoSuspend = !needDisplaySuspendBlocker;
+
+        // Disable auto-suspend if needed.
+        if (!autoSuspend) {
+            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+                setAutoSuspendModeLocked(false);
+            }
+            if (mDecoupleInteractiveModeFromDisplayConfig) {
+                setInteractiveModeLocked(true);
+            }
+        }
 
         // First acquire suspend blockers if needed.
         if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1627,17 +1749,27 @@
             mDisplaySuspendBlocker.release();
             mHoldingDisplaySuspendBlocker = false;
         }
+
+        // Enable auto-suspend if needed.
+        if (autoSuspend) {
+            if (mDecoupleInteractiveModeFromDisplayConfig) {
+                setInteractiveModeLocked(false);
+            }
+            if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+                setAutoSuspendModeLocked(true);
+            }
+        }
     }
 
     /**
      * Return true if we must keep a suspend blocker active on behalf of the display.
      * We do so if the screen is on or is in transition between states.
      */
-    private boolean needDisplaySuspendBlocker() {
+    private boolean needDisplaySuspendBlockerLocked() {
         if (!mDisplayReady) {
             return true;
         }
-        if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+        if (mDisplayPowerRequest.wantScreenOnNormal()) {
             // If we asked for the screen to be on but it is off due to the proximity
             // sensor then we may suspend but only if the configuration allows it.
             // On some hardware it may not be safe to suspend because the proximity
@@ -1647,13 +1779,34 @@
                 return true;
             }
         }
+        // Let the system suspend if the screen is off or dozing.
         return false;
     }
 
+    private void setAutoSuspendModeLocked(boolean enable) {
+        if (enable != mAutoSuspendModeEnabled) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+            }
+            mAutoSuspendModeEnabled = enable;
+            nativeSetAutoSuspend(enable);
+        }
+    }
+
+    private void setInteractiveModeLocked(boolean enable) {
+        if (enable != mInteractiveModeEnabled) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting interactive mode to " + enable);
+            }
+            mInteractiveModeEnabled = enable;
+            nativeSetInteractive(enable);
+        }
+    }
+
     private boolean isScreenOnInternal() {
         synchronized (mLock) {
             return !mSystemReady
-                    || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
+                    || mDisplayPowerRequest.wantScreenOnNormal();
         }
     }
 
@@ -1871,10 +2024,13 @@
             pw.println("  mProximityPositive=" + mProximityPositive);
             pw.println("  mBootCompleted=" + mBootCompleted);
             pw.println("  mSystemReady=" + mSystemReady);
+            pw.println("  mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
+            pw.println("  mInteactiveModeEnabled=" + mInteractiveModeEnabled);
             pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
             pw.println("  mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
             pw.println("  mSandmanScheduled=" + mSandmanScheduled);
+            pw.println("  mSandmanSummoned=" + mSandmanSummoned);
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
             pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
             pw.println("  mSendWakeUpFinishedNotificationWhenReady="
@@ -1890,6 +2046,10 @@
 
             pw.println();
             pw.println("Settings and Configuration:");
+            pw.println("  mDecoupleAutoSuspendModeFromDisplayConfig="
+                    + mDecoupleAutoSuspendModeFromDisplayConfig);
+            pw.println("  mDecoupleInteractiveModeFromDisplayConfig="
+                    + mDecoupleInteractiveModeFromDisplayConfig);
             pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
                     + mWakeUpWhenPluggedOrUnpluggedConfig);
             pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
@@ -1900,6 +2060,14 @@
                     + mDreamsActivatedOnSleepByDefaultConfig);
             pw.println("  mDreamsActivatedOnDockByDefaultConfig="
                     + mDreamsActivatedOnDockByDefaultConfig);
+            pw.println("  mDreamsEnabledOnBatteryConfig="
+                    + mDreamsEnabledOnBatteryConfig);
+            pw.println("  mDreamsBatteryLevelMinimumWhenPoweredConfig="
+                    + mDreamsBatteryLevelMinimumWhenPoweredConfig);
+            pw.println("  mDreamsBatteryLevelMinimumWhenNotPoweredConfig="
+                    + mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+            pw.println("  mDreamsBatteryLevelDrainCutoffConfig="
+                    + mDreamsBatteryLevelDrainCutoffConfig);
             pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
             pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
             pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
@@ -1975,8 +2143,8 @@
                 return "Awake";
             case WAKEFULNESS_DREAMING:
                 return "Dreaming";
-            case WAKEFULNESS_NAPPING:
-                return "Napping";
+            case WAKEFULNESS_DOZING:
+                return "Dozing";
             default:
                 return Integer.toString(wakefulness);
         }
@@ -2153,6 +2321,7 @@
                     + " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
         }
 
+        @SuppressWarnings("deprecation")
         private String getLockLevelString() {
             switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                 case PowerManager.FULL_WAKE_LOCK:
@@ -2165,6 +2334,8 @@
                     return "PARTIAL_WAKE_LOCK             ";
                 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                     return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
+                case PowerManager.DOZE_WAKE_LOCK:
+                    return "DOZE_WAKE_LOCK                ";
                 default:
                     return "???                           ";
             }
@@ -2295,16 +2466,24 @@
             synchronized (this) {
                 mBlanked = true;
                 mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
-                nativeSetInteractive(false);
-                nativeSetAutoSuspend(true);
+                if (!mDecoupleInteractiveModeFromDisplayConfig) {
+                    setInteractiveModeLocked(false);
+                }
+                if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+                    setAutoSuspendModeLocked(true);
+                }
             }
         }
 
         @Override
         public void unblankAllDisplays() {
             synchronized (this) {
-                nativeSetAutoSuspend(false);
-                nativeSetInteractive(true);
+                if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+                    setAutoSuspendModeLocked(false);
+                }
+                if (!mDecoupleInteractiveModeFromDisplayConfig) {
+                    setInteractiveModeLocked(true);
+                }
                 mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
                 mBlanked = false;
             }
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index aa7d485..8f6a8ff 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -125,12 +125,53 @@
         }
     }
 
+    /**
+     * @param layer The new layer value.
+     * @param inTransaction Whether the call is made within a surface transaction.
+     */
+    void adjustSurface(int layer, boolean inTransaction) {
+        final int dw, dh;
+        final float xPos, yPos;
+        if (!mStack.isFullscreen()) {
+            dw = mBounds.width();
+            dh = mBounds.height();
+            xPos = mBounds.left;
+            yPos = mBounds.top;
+        } else {
+            // Set surface size to screen size.
+            final DisplayInfo info = mDisplayContent.getDisplayInfo();
+            // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose
+            // a corner.
+            dw = (int) (info.logicalWidth * 1.5);
+            dh = (int) (info.logicalHeight * 1.5);
+            // back off position so 1/4 of Surface is before and 1/4 is after.
+            xPos = -1 * dw / 6;
+            yPos = -1 * dh / 6;
+        }
+
+        try {
+            if (!inTransaction) {
+                SurfaceControl.openTransaction();
+            }
+            mDimSurface.setPosition(xPos, yPos);
+            mDimSurface.setSize(dw, dh);
+            mDimSurface.setLayer(layer);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Failure setting size or layer", e);
+        } finally {
+            if (!inTransaction) {
+                SurfaceControl.closeTransaction();
+            }
+        }
+        mLastBounds.set(mBounds);
+        mLayer = layer;
+    }
+
+    // Assumes that surface transactions are currently closed.
     void setBounds(Rect bounds) {
         mBounds.set(bounds);
         if (isDimming() && !mLastBounds.equals(bounds)) {
-            // Clearing mAlpha forces show to redisplay with new size. 
-            mAlpha = 0;
-            show();
+            adjustSurface(mLayer, false);
         }
     }
 
@@ -169,35 +210,8 @@
             return;
         }
 
-        final int dw, dh;
-        final float xPos, yPos;
-        if (!mStack.isFullscreen()) {
-            dw = mBounds.width();
-            dh = mBounds.height();
-            xPos = mBounds.left;
-            yPos = mBounds.top;
-        } else {
-            // Set surface size to screen size.
-            final DisplayInfo info = mDisplayContent.getDisplayInfo();
-            // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
-            // corner.
-            dw = (int) (info.logicalWidth * 1.5);
-            dh = (int) (info.logicalHeight * 1.5);
-            // back off position so 1/4 of Surface is before and 1/4 is after.
-            xPos = -1 * dw / 6;
-            yPos = -1 * dh / 6;
-        }
-
         if (!mLastBounds.equals(mBounds) || mLayer != layer) {
-            try {
-                mDimSurface.setPosition(xPos, yPos);
-                mDimSurface.setSize(dw, dh);
-                mDimSurface.setLayer(layer);
-            } catch (RuntimeException e) {
-                Slog.w(TAG, "Failure setting size or layer", e);
-            }
-            mLastBounds.set(mBounds);
-            mLayer = layer;
+            adjustSurface(layer, true);
         }
 
         long curTime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 803b9ac..4aae5c1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -364,8 +364,8 @@
      * motion event processing when the screen is off since these events are normally
      * dropped. */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
-        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+    public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1a3ce63..d1cfff4 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -6,6 +6,7 @@
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp
new file mode 100644
index 0000000..a6d9297
--- /dev/null
+++ b/services/core/jni/com_android_server_dreams_McuHal.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#define LOG_TAG "McuHal"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <hardware/mcu.h>
+
+namespace android {
+
+static jlong nativeOpen(JNIEnv* env, jclass clazz) {
+    mcu_module_t* module = NULL;
+    status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&module);
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+        return 0;
+    }
+
+    err = module->init(module);
+    if (err) {
+        ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+        return 0;
+    }
+
+    return reinterpret_cast<jlong>(module);
+}
+
+static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz,
+        jlong ptr, jstring msgStr, jbyteArray argArray) {
+    mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr);
+
+    ScopedUtfChars msg(env, msgStr);
+    ALOGV("Sending message %s to MCU", msg.c_str());
+
+    void* result = NULL;
+    size_t resultSize = 0;
+    status_t err;
+    if (argArray) {
+        ScopedByteArrayRO arg(env, argArray);
+        err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(),
+                &result, &resultSize);
+    } else {
+        err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize);
+    }
+    if (err) {
+        ALOGE("Couldn't send message to MCU (%s)", strerror(-err));
+        return NULL;
+    }
+
+    if (!result) {
+        return NULL;
+    }
+
+    jbyteArray resultArray = env->NewByteArray(resultSize);
+    if (resultArray) {
+        env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result));
+    }
+    free(result);
+    return resultArray;
+}
+
+static JNINativeMethod gMcuHalMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeOpen", "()J",
+            (void*) nativeOpen },
+    { "nativeSendMessage", "(JLjava/lang/String;[B)[B",
+            (void*) nativeSendMessage },
+};
+
+int register_android_server_dreams_McuHal(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal",
+            gMcuHalMethods, NELEM(gMcuHalMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 0542ce0..697f56d 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -144,8 +144,6 @@
 
 enum {
     WM_ACTION_PASS_TO_USER = 1,
-    WM_ACTION_WAKE_UP = 2,
-    WM_ACTION_GO_TO_SLEEP = 4,
 };
 
 
@@ -834,7 +832,7 @@
             JNIEnv* env = jniEnv();
             jint wmActions = env->CallIntMethod(mServiceObj,
                         gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
-                        policyFlags);
+                        when, policyFlags);
             if (checkAndClearExceptionFromCallback(env,
                     "interceptMotionBeforeQueueingWhenScreenOff")) {
                 wmActions = 0;
@@ -850,20 +848,6 @@
 
 void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
         uint32_t& policyFlags) {
-    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-        ALOGD("handleInterceptActions: Going to sleep.");
-#endif
-        android_server_PowerManagerService_goToSleep(when);
-    }
-
-    if (wmActions & WM_ACTION_WAKE_UP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-        ALOGD("handleInterceptActions: Waking up.");
-#endif
-        android_server_PowerManagerService_wakeUp(when);
-    }
-
     if (wmActions & WM_ACTION_PASS_TO_USER) {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
     } else {
@@ -1402,7 +1386,7 @@
 
     GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
             clazz,
-            "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
+            "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index efc34a2..00986d5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,6 +36,7 @@
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_AssetAtlasService(JNIEnv* env);
+int register_android_server_dreams_McuHal(JNIEnv* env);
 };
 
 using namespace android;
@@ -67,7 +68,7 @@
     register_android_server_connectivity_Vpn(env);
     register_android_server_AssetAtlasService(env);
     register_android_server_ConsumerIrService(env);
-
+    register_android_server_dreams_McuHal(env);
 
     return JNI_VERSION_1_4;
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index afd7845..0e056eb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -112,6 +112,8 @@
             "com.android.server.appwidget.AppWidgetService";
     private static final String PRINT_MANAGER_SERVICE_CLASS =
             "com.android.server.print.PrintManagerService";
+    private static final String USB_SERVICE_CLASS =
+            "com.android.server.usb.UsbService$Lifecycle";
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
@@ -534,8 +536,7 @@
 
                 try {
                     if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
-                        mSystemServiceManager.startServiceIfExists(
-                                DEVICE_POLICY_MANAGER_SERVICE_CLASS);
+                        mSystemServiceManager.startService(DEVICE_POLICY_MANAGER_SERVICE_CLASS);
                     }
                 } catch (Throwable e) {
                     reportWtf("starting DevicePolicyService", e);
@@ -761,10 +762,11 @@
 
             if (!disableNonCoreServices) {
                 try {
-                    Slog.i(TAG, "USB Service");
-                    // Manage USB host and device support
-                    usb = new UsbService(context);
-                    ServiceManager.addService(Context.USB_SERVICE, usb);
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST) ||
+                            pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) {
+                        // Manage USB host and device support
+                        mSystemServiceManager.startService(USB_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     reportWtf("starting UsbService", e);
                 }
@@ -786,7 +788,7 @@
             if (!disableNonCoreServices) {
                 try {
                     if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
-                        mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
+                        mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
                     }
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting Backup Service", e);
@@ -794,7 +796,7 @@
 
                 try {
                     if (pm.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
-                        mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
+                        mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
                     }
                 } catch (Throwable e) {
                     reportWtf("starting AppWidget Service", e);
@@ -880,7 +882,7 @@
 
             try {
                 if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
-                    mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
+                    mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
                 }
             } catch (Throwable e) {
                 reportWtf("starting Print Service", e);
@@ -972,7 +974,6 @@
         }
 
         // These are needed to propagate to the runnable below.
-        final Context contextF = context;
         final MountService mountServiceF = mountService;
         final BatteryService batteryF = battery;
         final NetworkManagementService networkManagementF = networkManagement;
@@ -980,7 +981,6 @@
         final NetworkPolicyManagerService networkPolicyF = networkPolicy;
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
-        final UsbService usbF = usb;
         final WallpaperManagerService wallpaperF = wallpaper;
         final InputMethodManagerService immF = imm;
         final RecognitionManagerService recognitionF = recognition;
@@ -1000,132 +1000,138 @@
         // where third party code can really run (but before it has actually
         // started launching the initial applications), for us to complete our
         // initialization.
+        final Handler handler = new Handler();
         mActivityManagerService.systemReady(new Runnable() {
+            @Override
             public void run() {
-                Slog.i(TAG, "Making services ready");
+                // We initiate all boot phases on the SystemServer thread.
+                handler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Slog.i(TAG, "Making services ready");
+                        mSystemServiceManager.startBootPhase(
+                                SystemService.PHASE_ACTIVITY_MANAGER_READY);
 
-                try {
-                    mActivityManagerService.startObservingNativeCrashes();
-                } catch (Throwable e) {
-                    reportWtf("observing native crashes", e);
-                }
-                try {
-                    startSystemUi(contextF);
-                } catch (Throwable e) {
-                    reportWtf("starting System UI", e);
-                }
-                try {
-                    if (mountServiceF != null) mountServiceF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Mount Service ready", e);
-                }
-                try {
-                    if (batteryF != null) batteryF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Battery Service ready", e);
-                }
-                try {
-                    if (networkManagementF != null) networkManagementF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Network Managment Service ready", e);
-                }
-                try {
-                    if (networkStatsF != null) networkStatsF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Network Stats Service ready", e);
-                }
-                try {
-                    if (networkPolicyF != null) networkPolicyF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Network Policy Service ready", e);
-                }
-                try {
-                    if (connectivityF != null) connectivityF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Connectivity Service ready", e);
-                }
-                try {
-                    if (dockF != null) dockF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Dock Service ready", e);
-                }
-                try {
-                    if (usbF != null) usbF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making USB Service ready", e);
-                }
-                try {
-                    if (recognitionF != null) recognitionF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making Recognition Service ready", e);
-                }
-                Watchdog.getInstance().start();
+                        try {
+                            mActivityManagerService.startObservingNativeCrashes();
+                        } catch (Throwable e) {
+                            reportWtf("observing native crashes", e);
+                        }
+                        try {
+                            startSystemUi(context);
+                        } catch (Throwable e) {
+                            reportWtf("starting System UI", e);
+                        }
+                        try {
+                            if (mountServiceF != null) mountServiceF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Mount Service ready", e);
+                        }
+                        try {
+                            if (batteryF != null) batteryF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Battery Service ready", e);
+                        }
+                        try {
+                            if (networkManagementF != null) networkManagementF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Network Managment Service ready", e);
+                        }
+                        try {
+                            if (networkStatsF != null) networkStatsF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Network Stats Service ready", e);
+                        }
+                        try {
+                            if (networkPolicyF != null) networkPolicyF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Network Policy Service ready", e);
+                        }
+                        try {
+                            if (connectivityF != null) connectivityF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Connectivity Service ready", e);
+                        }
+                        try {
+                            if (dockF != null) dockF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Dock Service ready", e);
+                        }
+                        try {
+                            if (recognitionF != null) recognitionF.systemReady();
+                        } catch (Throwable e) {
+                            reportWtf("making Recognition Service ready", e);
+                        }
+                        Watchdog.getInstance().start();
 
-                // It is now okay to let the various system services start their
-                // third party code...
-                mSystemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+                        // It is now okay to let the various system services start their
+                        // third party code...
+                        mSystemServiceManager.startBootPhase(
+                                SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
 
-                try {
-                    if (wallpaperF != null) wallpaperF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying WallpaperService running", e);
-                }
-                try {
-                    if (immF != null) immF.systemRunning(statusBarF);
-                } catch (Throwable e) {
-                    reportWtf("Notifying InputMethodService running", e);
-                }
-                try {
-                    if (locationF != null) locationF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying Location Service running", e);
-                }
-                try {
-                    if (countryDetectorF != null) countryDetectorF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying CountryDetectorService running", e);
-                }
-                try {
-                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying NetworkTimeService running", e);
-                }
-                try {
-                    if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying CommonTimeManagementService running", e);
-                }
-                try {
-                    if (textServiceManagerServiceF != null)
-                        textServiceManagerServiceF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying TextServicesManagerService running", e);
-                }
-                try {
-                    if (atlasF != null) atlasF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying AssetAtlasService running", e);
-                }
-                try {
-                    // TODO(BT) Pass parameter to input manager
-                    if (inputManagerF != null) inputManagerF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying InputManagerService running", e);
-                }
+                        try {
+                            if (wallpaperF != null) wallpaperF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying WallpaperService running", e);
+                        }
+                        try {
+                            if (immF != null) immF.systemRunning(statusBarF);
+                        } catch (Throwable e) {
+                            reportWtf("Notifying InputMethodService running", e);
+                        }
+                        try {
+                            if (locationF != null) locationF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying Location Service running", e);
+                        }
+                        try {
+                            if (countryDetectorF != null) countryDetectorF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying CountryDetectorService running", e);
+                        }
+                        try {
+                            if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying NetworkTimeService running", e);
+                        }
+                        try {
+                            if (commonTimeMgmtServiceF != null) {
+                                commonTimeMgmtServiceF.systemRunning();
+                            }
+                        } catch (Throwable e) {
+                            reportWtf("Notifying CommonTimeManagementService running", e);
+                        }
+                        try {
+                            if (textServiceManagerServiceF != null)
+                                textServiceManagerServiceF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying TextServicesManagerService running", e);
+                        }
+                        try {
+                            if (atlasF != null) atlasF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying AssetAtlasService running", e);
+                        }
+                        try {
+                            // TODO(BT) Pass parameter to input manager
+                            if (inputManagerF != null) inputManagerF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying InputManagerService running", e);
+                        }
+                        try {
+                            if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying TelephonyRegistry running", e);
+                        }
+                        try {
+                            if (mediaRouterF != null) mediaRouterF.systemRunning();
+                        } catch (Throwable e) {
+                            reportWtf("Notifying MediaRouterService running", e);
+                        }
 
-                try {
-                    if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying TelephonyRegistry running", e);
-                }
-
-                try {
-                    if (mediaRouterF != null) mediaRouterF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying MediaRouterService running", e);
-                }
-
-                mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
+                        mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
+                    }
+                });
             }
         });
     }
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
new file mode 100644
index 0000000..feabf0a
--- /dev/null
+++ b/services/usb/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.usb
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
similarity index 100%
rename from services/core/java/com/android/server/usb/UsbDebuggingManager.java
rename to services/usb/java/com/android/server/usb/UsbDebuggingManager.java
diff --git a/services/core/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
similarity index 99%
rename from services/core/java/com/android/server/usb/UsbDeviceManager.java
rename to services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 5a60de0..9a4d8d8 100644
--- a/services/core/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -812,7 +812,7 @@
                     if (mOemModeMap == null) {
                         mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
                     }
-                    List overrideList = mOemModeMap.get(items[0]);
+                    List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
                     if (overrideList == null) {
                         overrideList = new LinkedList<Pair<String, String>>();
                         mOemModeMap.put(items[0], overrideList);
diff --git a/services/core/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
similarity index 100%
rename from services/core/java/com/android/server/usb/UsbHostManager.java
rename to services/usb/java/com/android/server/usb/UsbHostManager.java
diff --git a/services/core/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
similarity index 94%
rename from services/core/java/com/android/server/usb/UsbService.java
rename to services/usb/java/com/android/server/usb/UsbService.java
index 36669b1..b6ae192 100644
--- a/services/core/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemService;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -43,6 +44,28 @@
  * support is delegated to UsbDeviceManager.
  */
 public class UsbService extends IUsbManager.Stub {
+
+    public static class Lifecycle extends SystemService {
+        private UsbService mUsbService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mUsbService = new UsbService(getContext());
+            publishBinderService(Context.USB_SERVICE, mUsbService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mUsbService.systemReady();
+            }
+        }
+    }
+
     private static final String TAG = "UsbService";
 
     private final Context mContext;
diff --git a/services/core/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
similarity index 100%
rename from services/core/java/com/android/server/usb/UsbSettingsManager.java
rename to services/usb/java/com/android/server/usb/UsbSettingsManager.java
diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk
new file mode 100644
index 0000000..01f10e5
--- /dev/null
+++ b/tests/DozeTest/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := DozeTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml
new file mode 100644
index 0000000..c199f69
--- /dev/null
+++ b/tests/DozeTest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.dreams.dozetest">
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application android:label="@string/app_name">
+        <service
+            android:name="DozeTestDream"
+            android:exported="true"
+            android:icon="@drawable/ic_app"
+            android:label="@string/doze_dream_name">
+            <!-- Commented out to prevent this dream from appearing in the list of
+                 dreams that the user can select via the Settings application.
+            <intent-filter>
+                <action android:name="android.service.dreams.DreamService" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            -->
+        </service>
+    </application>
+</manifest>
diff --git a/tests/DozeTest/res/drawable-hdpi/ic_app.png b/tests/DozeTest/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/DozeTest/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/drawable-mdpi/ic_app.png b/tests/DozeTest/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/DozeTest/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml
new file mode 100644
index 0000000..1c8fd3f
--- /dev/null
+++ b/tests/DozeTest/res/layout/dream.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:orientation="vertical">
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/alarm_clock_label" />
+    <TextView android:id="@+id/alarm_clock"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    <Space
+            android:layout_width="match_parent"
+            android:layout_height="32dp" />
+
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/tick_clock_label" />
+    <TextClock android:id="@+id/tick_clock"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/DozeTest/res/values/strings.xml b/tests/DozeTest/res/values/strings.xml
new file mode 100644
index 0000000..f21911f
--- /dev/null
+++ b/tests/DozeTest/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+    <!-- Name of the package of basic screensavers, shown in Settings > Apps. [CHAR LIMIT=40] -->
+    <string name="app_name">Doze Test</string>
+
+    <!-- Name of the screensaver. [CHAR LIMIT=40] -->
+    <string name="doze_dream_name">Doze Test</string>
+
+    <string name="alarm_clock_label">This clock is updated using the Alarm Manager</string>
+    <string name="tick_clock_label">This clock is updated using TIME_TICK Broadcasts</string>
+</resources>
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
new file mode 100644
index 0000000..bf35db4
--- /dev/null
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 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 com.android.dreams.dozetest;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.service.dreams.DozeHardware;
+import android.service.dreams.DreamService;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.widget.TextView;
+
+import java.util.Date;
+
+/**
+ * Simple test for doze mode.
+ * <p>
+ * adb shell setprop debug.doze.component com.android.dreams.dozetest/.DozeTestDream
+ * </p>
+ */
+public class DozeTestDream extends DreamService {
+    private static final String TAG = DozeTestDream.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    // Amount of time to allow to update the time shown on the screen before releasing
+    // the wakelock.  This timeout is design to compensate for the fact that we don't
+    // currently have a way to know when time display contents have actually been
+    // refreshed once the dream has finished rendering a new frame.
+    private static final int UPDATE_TIME_TIMEOUT = 100;
+
+    // A doze hardware message string we use for end-to-end testing.
+    // Doesn't mean anything.  Real hardware won't handle it.
+    private static final String TEST_PING_MESSAGE = "test.ping";
+
+    private PowerManager mPowerManager;
+    private PowerManager.WakeLock mWakeLock;
+    private AlarmManager mAlarmManager;
+    private PendingIntent mAlarmIntent;
+
+    private TextView mAlarmClock;
+
+    private final Date mTime = new Date();
+    private java.text.DateFormat mTimeFormat;
+
+    private boolean mDreaming;
+    private DozeHardware mDozeHardware;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+        mAlarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
+
+        Intent intent = new Intent("com.android.dreams.dozetest.ACTION_ALARM");
+        intent.setPackage(getPackageName());
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(intent.getAction());
+        registerReceiver(mAlarmReceiver, filter);
+        mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        unregisterReceiver(mAlarmReceiver);
+        mAlarmIntent.cancel();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        setInteractive(false);
+        setLowProfile(true);
+        setFullscreen(true);
+        setContentView(R.layout.dream);
+
+        mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
+
+        mTimeFormat = DateFormat.getTimeFormat(this);
+    }
+
+    @Override
+    public void onDreamingStarted() {
+        super.onDreamingStarted();
+
+        mDreaming = true;
+        mDozeHardware = getDozeHardware();
+
+        Log.d(TAG, "Dream started: canDoze=" + canDoze()
+                + ", dozeHardware=" + mDozeHardware);
+
+        performTimeUpdate();
+
+        if (mDozeHardware != null) {
+            mDozeHardware.sendMessage(TEST_PING_MESSAGE, null);
+            mDozeHardware.setEnableMcu(true);
+        }
+        startDozing();
+    }
+
+    @Override
+    public void onDreamingStopped() {
+        super.onDreamingStopped();
+
+        mDreaming = false;
+        if (mDozeHardware != null) {
+            mDozeHardware.setEnableMcu(false);
+            mDozeHardware = null;
+        }
+
+        Log.d(TAG, "Dream ended: isDozing=" + isDozing());
+
+        stopDozing();
+        cancelTimeUpdate();
+    }
+
+    private void performTimeUpdate() {
+        if (mDreaming) {
+            long now = System.currentTimeMillis();
+            now -= now % 60000; // back up to last minute boundary
+
+            mTime.setTime(now);
+            mAlarmClock.setText(mTimeFormat.format(mTime));
+
+            mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent);
+
+            mWakeLock.acquire(UPDATE_TIME_TIMEOUT);
+        }
+    }
+
+    private void cancelTimeUpdate() {
+        mAlarmManager.cancel(mAlarmIntent);
+    }
+
+    private final BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            performTimeUpdate();
+        }
+    };
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index a25fb59..60cd157 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -103,6 +103,9 @@
         if (familyName == null) {
             familyName = DEFAULT_FAMILY;
         }
+        if (style < 0) {
+            style = Typeface.NORMAL;
+        }
 
         Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style);
         if (sFontLoader != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
index 108b651..cc7338a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
@@ -57,7 +57,9 @@
     private static final String FONT_SUFFIX_NONE = ".ttf";
     private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf";
     private static final String FONT_SUFFIX_BOLD = "-Bold.ttf";
-    private static final String FONT_SUFFIX_ITALIC = "-Italic.ttf";
+    // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked
+    // separately.
+    private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
     private static final String FONT_SUFFIX_BOLDITALIC = "-BoldItalic.ttf";
 
     // This must match the values of Typeface styles so that we can use them for indices in this
@@ -285,10 +287,10 @@
                             mFontInfo.font[Typeface.NORMAL] = font;
                         } else if (fileName.endsWith(FONT_SUFFIX_BOLD)) {
                             mFontInfo.font[Typeface.BOLD] = font;
-                        } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) {
-                            mFontInfo.font[Typeface.ITALIC] = font;
                         } else if (fileName.endsWith(FONT_SUFFIX_BOLDITALIC)) {
                             mFontInfo.font[Typeface.BOLD_ITALIC] = font;
+                        } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) {
+                            mFontInfo.font[Typeface.ITALIC] = font;
                         } else if (fileName.endsWith(FONT_SUFFIX_NONE)) {
                             mFontInfo.font[Typeface.NORMAL] = font;
                         }