Merge "First step towards cleaning up Global settings." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 5224491..91e5ddd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10665,7 +10665,7 @@
     method public float getAccuracy();
     method public double getAltitude();
     method public float getBearing();
-    method public long getElapsedRealtimeNano();
+    method public long getElapsedRealtimeNanos();
     method public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
@@ -10685,7 +10685,7 @@
     method public void setAccuracy(float);
     method public void setAltitude(double);
     method public void setBearing(float);
-    method public void setElapsedRealtimeNano(long);
+    method public void setElapsedRealtimeNanos(long);
     method public void setExtras(android.os.Bundle);
     method public void setLatitude(double);
     method public void setLongitude(double);
@@ -12745,14 +12745,12 @@
     method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
     method public java.lang.String[] getDefaultCipherSuites();
     method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
-    method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
     method public byte[] getNpnSelectedProtocol(java.net.Socket);
     method public java.lang.String[] getSupportedCipherSuites();
     method public void setHostname(java.net.Socket, java.lang.String);
     method public void setKeyManagers(javax.net.ssl.KeyManager[]);
     method public void setNpnProtocols(byte[][]);
-    method public void setSoWriteTimeout(java.net.Socket, int) throws java.net.SocketException;
     method public void setTrustManagers(javax.net.ssl.TrustManager[]);
     method public void setUseSessionTickets(java.net.Socket, boolean);
   }
@@ -16576,7 +16574,7 @@
   public final class SystemClock {
     method public static long currentThreadTimeMillis();
     method public static long elapsedRealtime();
-    method public static long elapsedRealtimeNano();
+    method public static long elapsedRealtimeNanos();
     method public static boolean setCurrentTimeMillis(long);
     method public static void sleep(long);
     method public static long uptimeMillis();
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 4257e0e..4999a2d 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -203,6 +203,12 @@
         }
     };
 
+    private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            onAccountsUpdated(null);
+        }
+    };
+
     private final PowerManager mPowerManager;
 
     // Use this as a random offset to seed all periodic syncs
@@ -456,8 +462,11 @@
         });
 
         if (!factoryTest) {
-            AccountManager.get(mContext).addOnAccountsUpdatedListener(SyncManager.this,
-                mSyncHandler, false /* updateImmediately */);
+            // Register for account list updates for all users
+            mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
+                    UserHandle.ALL,
+                    new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
+                    null, null);
             // do this synchronously to ensure we have the accounts before this call returns
             onAccountsUpdated(null);
         }
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 42fb5c3..846443d 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -90,7 +90,6 @@
     private byte[] mNpnProtocols = null;
 
     private final int mHandshakeTimeoutMillis;
-    private final int mWriteTimeoutMillis;
     private final SSLClientSessionCache mSessionCache;
     private final boolean mSecure;
 
@@ -101,21 +100,12 @@
     }
 
     private SSLCertificateSocketFactory(
-            int handshakeTimeoutMillis,
-            int writeTimeoutMillis,
-            SSLSessionCache cache,
-            boolean secure) {
+            int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) {
         mHandshakeTimeoutMillis = handshakeTimeoutMillis;
-        mWriteTimeoutMillis = writeTimeoutMillis;
         mSessionCache = cache == null ? null : cache.mSessionCache;
         mSecure = secure;
     }
 
-    private SSLCertificateSocketFactory(
-            int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) {
-        this(handshakeTimeoutMillis, 0, cache, secure);
-    }
-
     /**
      * Returns a new socket factory instance with an optional handshake timeout.
      *
@@ -172,24 +162,6 @@
     }
 
     /**
-     * Returns a socket factory (also named SSLSocketFactory, but in a different
-     * namespace) for use with the Apache HTTP stack.
-     *
-     * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
-     *         for none.  The socket timeout is reset to 0 after the handshake.
-     * @param writeTimeoutMillis the desired write timeout in milliseconds or 0 for none.
-     * @param cache The {@link SSLSessionCache} to use, or null for no cache.
-     * @return a new SocketFactory with the specified parameters
-     */
-    public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
-            int handshakeTimeoutMillis,
-            int writeTimeoutMillis,
-            SSLSessionCache cache) {
-        return new org.apache.http.conn.ssl.SSLSocketFactory(new SSLCertificateSocketFactory(
-                handshakeTimeoutMillis, writeTimeoutMillis, cache, true));
-    }
-
-    /**
      * Verify the hostname of the certificate used by the other end of a
      * connected socket.  You MUST call this if you did not supply a hostname
      * to {@link #createSocket()}.  It is harmless to call this method
@@ -376,8 +348,10 @@
      * To take effect, this option must be set before the blocking method was called.
      *
      * @param socket a socket created by this factory.
-     * @param writeTimeoutMilliseconds the desired write timeout in milliseconds.
+     * @param timeout the desired write timeout in milliseconds.
      * @throws IllegalArgumentException if the socket was not created by this factory.
+     *
+     * @hide
      */
     public void setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds)
             throws SocketException {
@@ -404,7 +378,6 @@
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
         s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        s.setSoWriteTimeout(mWriteTimeoutMillis);
         if (mSecure) {
             verifyHostname(s, host);
         }
@@ -424,7 +397,6 @@
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
         s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        s.setSoWriteTimeout(mWriteTimeoutMillis);
         return s;
     }
 
@@ -442,7 +414,6 @@
                 addr, port, localAddr, localPort);
         s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        s.setSoWriteTimeout(mWriteTimeoutMillis);
         return s;
     }
 
@@ -458,7 +429,6 @@
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
         s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        s.setSoWriteTimeout(mWriteTimeoutMillis);
         return s;
     }
 
@@ -475,7 +445,6 @@
                 host, port, localAddr, localPort);
         s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        s.setSoWriteTimeout(mWriteTimeoutMillis);
         if (mSecure) {
             verifyHostname(s, host);
         }
@@ -493,7 +462,6 @@
         OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
         s.setNpnProtocols(mNpnProtocols);
         s.setHandshakeTimeout(mHandshakeTimeoutMillis);
-        s.setSoWriteTimeout(mWriteTimeoutMillis);
         if (mSecure) {
             verifyHostname(s, host);
         }
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 8169a94..c534e58 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -16,16 +16,7 @@
 
 package android.net.http;
 
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.SSLCertificateSocketFactory;
-import android.net.SSLSessionCache;
-import android.os.Looper;
-import android.util.Base64;
-import android.util.Log;
-
 import com.android.internal.http.HttpDateTime;
-
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
@@ -34,18 +25,18 @@
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpRequestInterceptor;
 import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
+import org.apache.http.entity.AbstractHttpEntity;
+import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.protocol.ClientContext;
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
 import org.apache.http.conn.ClientConnectionManager;
 import org.apache.http.conn.scheme.PlainSocketFactory;
 import org.apache.http.conn.scheme.Scheme;
 import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.impl.client.RequestWrapper;
 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
@@ -53,17 +44,25 @@
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.BasicHttpProcessor;
 import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
-import java.net.URI;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
+import java.net.URI;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.net.SSLCertificateSocketFactory;
+import android.net.SSLSessionCache;
+import android.os.Looper;
+import android.util.Base64;
+import android.util.Log;
 
 /**
  * Implementation of the Apache {@link DefaultHttpClient} that is configured with
@@ -135,7 +134,7 @@
                 PlainSocketFactory.getSocketFactory(), 80));
         schemeRegistry.register(new Scheme("https",
                 SSLCertificateSocketFactory.getHttpSocketFactory(
-                SOCKET_OPERATION_TIMEOUT, SOCKET_OPERATION_TIMEOUT, sessionCache), 443));
+                SOCKET_OPERATION_TIMEOUT, sessionCache), 443));
 
         ClientConnectionManager manager =
                 new ThreadSafeClientConnManager(params, schemeRegistry);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 7aee644..eec19cb 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -34,6 +34,7 @@
     void userActivity(long time, int event, int flags);
     void wakeUp(long time);
     void goToSleep(long time, int reason);
+    void nap(long time);
 
     boolean isScreenOn();
     void reboot(String reason);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cc2c002..58372f4 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -426,7 +426,7 @@
      * </p>
      *
      * @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()}
-     * time base.  This timestamp is used to correctly order the user activity with
+     * time base.  This timestamp is used to correctly order the user activity request with
      * other power management functions.  It should be set
      * to the timestamp of the input event that caused the user activity.
      * @param noChangeLights If true, does not cause the keyboard backlight to turn on
@@ -457,7 +457,7 @@
      *
      * @param time The time when the request to go to sleep was issued, in the
      * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
-     * order the user activity with other power management functions.  It should be set
+     * order the go to sleep request with other power management functions.  It should be set
      * to the timestamp of the input event that caused the request to go to sleep.
      *
      * @see #userActivity
@@ -481,7 +481,7 @@
      *
      * @param time The time when the request to wake up was issued, in the
      * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
-     * order the user activity with other power management functions.  It should be set
+     * order the wake up request with other power management functions.  It should be set
      * to the timestamp of the input event that caused the request to wake up.
      *
      * @see #userActivity
@@ -495,6 +495,34 @@
     }
 
     /**
+     * Forces the device to start napping.
+     * <p>
+     * If the device is currently awake, starts dreaming, otherwise does nothing.
+     * When the dream ends or if the dream cannot be started, the device will
+     * either wake up or go to sleep depending on whether there has been recent
+     * user activity.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * @param time The time when the request to nap was issued, in the
+     * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
+     * order the nap request with other power management functions.  It should be set
+     * to the timestamp of the input event that caused the request to nap.
+     *
+     * @see #wakeUp
+     * @see #goToSleep
+     *
+     * @hide
+     */
+    public void nap(long time) {
+        try {
+            mService.nap(time);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Sets the brightness of the backlights (screen, keyboard, button).
      * <p>
      * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index a54c25b..c9adf45 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -50,7 +50,7 @@
  *     interval does not span device sleep.  Most methods that accept a
  *     timestamp value currently expect the {@link #uptimeMillis} clock.
  *
- *     <li> <p> {@link #elapsedRealtime} and {@link #elapsedRealtimeNano}
+ *     <li> <p> {@link #elapsedRealtime} and {@link #elapsedRealtimeNanos}
  *     return the time since the system was booted, and include deep sleep.
  *     This clock is guaranteed to be monotonic, and continues to tick even
  *     when the CPU is in power saving modes, so is the recommend basis
@@ -157,7 +157,7 @@
      *
      * @return elapsed nanoseconds since boot.
      */
-    public static native long elapsedRealtimeNano();
+    public static native long elapsedRealtimeNanos();
 
     /**
      * Returns milliseconds running in the current thread.
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index 473414c..590acfa 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -72,6 +72,12 @@
     private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
 
     /**
+     * The name of the dream manager service.
+     * @hide
+     */
+    public static final String DREAM_SERVICE = "dreams";
+
+    /**
      * Used with {@link Intent#ACTION_MAIN} to declare the necessary intent-filter for a dream.
      *
      * @see Dream
@@ -499,7 +505,7 @@
     // end public api
 
     private void loadSandman() {
-        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
+        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
     }
 
     private final void attach(IBinder windowToken) {
@@ -584,7 +590,7 @@
             mFinished = true;
 
             if (mSandman != null) {
-                mSandman.awakenSelf(mWindowToken);
+                mSandman.finishSelf(mWindowToken);
             } else {
                 Slog.w(TAG, "No dream manager found");
             }
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index bd1c524..1c1b390 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -30,5 +30,5 @@
     ComponentName getDefaultDreamComponent();
     void testDream(in ComponentName componentName);
     boolean isDreaming();
-    void awakenSelf(in IBinder token);
+    void finishSelf(in IBinder token);
 }
\ No newline at end of file
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 123ce2a..b0a2711 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -314,7 +314,7 @@
             }
         }
 
-        final boolean configChanged =
+        final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
                 action == MotionEvent.ACTION_POINTER_UP ||
                 action == MotionEvent.ACTION_POINTER_DOWN;
         final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
@@ -344,7 +344,7 @@
             if (skipIndex == i) continue;
 
             // Average touch major and touch minor and convert the resulting diameter into a radius.
-            final float touchSize = getAdjustedTouchHistory(event.getPointerId(i));
+            final float touchSize = getAdjustedTouchHistory(event.getPointerId(i)) / 2;
             devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
             devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
         }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 87396fb..7ca8322 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -789,6 +789,7 @@
                     if (resizeWidth) {
                         int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
                                 pleft + pright;
+                        widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
                         if (newWidth <= widthSize) {
                             widthSize = newWidth;
                             done = true;
@@ -799,6 +800,7 @@
                     if (!done && resizeHeight) {
                         int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
                                 ptop + pbottom;
+                        heightSize = resolveAdjustedSize(newHeight, mMaxHeight, heightMeasureSpec);
                         if (newHeight <= heightSize) {
                             heightSize = newHeight;
                         }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index bffbe11..4ad0819 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -436,9 +436,10 @@
             if (mBaseResolveList != null) {
                 mCurrentResolveList = mBaseResolveList;
             } else {
-                mCurrentResolveList = mPm.queryIntentActivities(
+                mCurrentResolveList = mPm.queryIntentActivitiesAsUser(
                         mIntent, PackageManager.MATCH_DEFAULT_ONLY
-                        | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
+                        | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0),
+                        UserHandle.getUserId(mLaunchedFromUid));
                 // Filter out any activities that the launched uid does not
                 // have permission for.  We don't do this when we have an explicit
                 // list of resolved activities, because that only happens when
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index 78f989a..5c135ee 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -137,7 +137,7 @@
             (void*) android_os_SystemClock_currentThreadTimeMicro },
     { "currentTimeMicro",             "()J",
             (void*) android_os_SystemClock_currentTimeMicro },
-    { "elapsedRealtimeNano",      "()J",
+    { "elapsedRealtimeNanos",      "()J",
             (void*) android_os_SystemClock_elapsedRealtimeNano },
 };
 int register_android_os_SystemClock(JNIEnv* env)
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicBlend.java b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
index 13c03af..65c69c0 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
@@ -36,17 +36,18 @@
      * @return ScriptIntrinsicBlend
      */
     public static ScriptIntrinsicBlend create(RenderScript rs, Element e) {
-        int id = rs.nScriptIntrinsicCreate(6, e.getID(rs));
+        // 7 comes from RS_SCRIPT_INTRINSIC_ID_BLEND in rsDefines.h
+        int id = rs.nScriptIntrinsicCreate(7, e.getID(rs));
         return new ScriptIntrinsicBlend(id, rs);
 
     }
 
     private void blend(int id, Allocation ain, Allocation aout) {
-        if (ain.getElement() != Element.U8_4(mRS)) {
-            throw new RSIllegalArgumentException("Input not of expected format.");
+        if (!ain.getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Input is not of expected format.");
         }
-        if (aout.getElement() != Element.U8_4(mRS)) {
-            throw new RSIllegalArgumentException("Output not of expected format.");
+        if (!aout.getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Output is not of expected format.");
         }
         forEach(id, ain, aout, null);
     }
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 5b1b57d..f0b5553 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -81,6 +81,7 @@
 
     if (mInitialized) {
         transform = addUniform("transform");
+        projection = addUniform("projection");
     }
 }
 
@@ -152,18 +153,20 @@
 
 void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
         const mat4& transformMatrix, bool offset) {
-    mat4 t(projectionMatrix);
+    mat4 p(projectionMatrix);
     if (offset) {
         // offset screenspace xy by an amount that compensates for typical precision
         // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
         // up and to the left.
         // This offset value is based on an assumption that some hardware may use as
         // little as 12.4 precision, so we offset by slightly more than 1/16.
-        t.translate(.375, .375, 0);
+        p.translate(.375, .375, 0);
     }
-    t.multiply(transformMatrix);
+
+    mat4 t(transformMatrix);
     t.multiply(modelViewMatrix);
 
+    glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
     glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
 }
 
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index b1cb446..7e3aacf 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -374,6 +374,11 @@
      */
     int transform;
 
+    /**
+     * Name of the projection uniform.
+     */
+    int projection;
+
 protected:
     /**
      * Adds an attribute with the specified name.
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 7bc2b37..f536ade 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -48,6 +48,7 @@
 const char* gVS_Header_Uniforms_TextureTransform =
         "uniform mat4 mainTextureTransform;\n";
 const char* gVS_Header_Uniforms =
+        "uniform mat4 projection;\n" \
         "uniform mat4 transform;\n";
 const char* gVS_Header_Uniforms_IsPoint =
         "uniform mediump float pointSize;\n";
@@ -104,28 +105,28 @@
 const char* gVS_Main_OutGradient[6] = {
         // Linear
         "    linear = vec2((screenSpace * position).x, 0.5);\n"
-        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
         "    linear = (screenSpace * position).x;\n"
-        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
 
         // Circular
         "    circular = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
         "    circular = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
 
         // Sweep
         "    sweep = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
         "    sweep = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
 };
 const char* gVS_Main_OutBitmapTexCoords =
         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
 const char* gVS_Main_OutPointBitmapTexCoords =
         "    outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
 const char* gVS_Main_Position =
-        "    gl_Position = transform * position;\n";
+        "    gl_Position = projection * transform * position;\n";
 const char* gVS_Main_PointSize =
         "    gl_PointSize = pointSize;\n";
 const char* gVS_Main_AALine =
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 672e378..f057ebc 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -71,7 +71,7 @@
 
     private String mProvider;
     private long mTime = 0;
-    private long mElapsedRealtimeNano = 0;
+    private long mElapsedRealtimeNanos = 0;
     private double mLatitude = 0.0;
     private double mLongitude = 0.0;
     private boolean mHasAltitude = false;
@@ -120,7 +120,7 @@
     public void set(Location l) {
         mProvider = l.mProvider;
         mTime = l.mTime;
-        mElapsedRealtimeNano = l.mElapsedRealtimeNano;
+        mElapsedRealtimeNanos = l.mElapsedRealtimeNanos;
         mLatitude = l.mLatitude;
         mLongitude = l.mLongitude;
         mHasAltitude = l.mHasAltitude;
@@ -140,7 +140,7 @@
     public void reset() {
         mProvider = null;
         mTime = 0;
-        mElapsedRealtimeNano = 0;
+        mElapsedRealtimeNanos = 0;
         mLatitude = 0;
         mLongitude = 0;
         mHasAltitude = false;
@@ -485,7 +485,7 @@
      *
      * <p>Note that the UTC time on a device is not monotonic: it
      * can jump forwards or backwards unpredictably. So always use
-     * {@link #getElapsedRealtimeNano} when calculating time deltas.
+     * {@link #getElapsedRealtimeNanos} when calculating time deltas.
      *
      * <p>On the other hand, {@link #getTime} is useful for presenting
      * a human readable time to the user, or for carefully comparing
@@ -515,7 +515,7 @@
      * Return the time of this fix, in elapsed real-time since system boot.
      *
      * <p>This value can be reliably compared to
-     * {@link android.os.SystemClock#elapsedRealtimeNano},
+     * {@link android.os.SystemClock#elapsedRealtimeNanos},
      * to calculate the age of a fix and to compare Location fixes. This
      * is reliable because elapsed real-time is guaranteed monotonic for
      * each system boot and continues to increment even when the system
@@ -526,8 +526,8 @@
      *
      * @return elapsed real-time of fix, in nanoseconds since system boot.
      */
-    public long getElapsedRealtimeNano() {
-        return mElapsedRealtimeNano;
+    public long getElapsedRealtimeNanos() {
+        return mElapsedRealtimeNanos;
     }
 
     /**
@@ -535,8 +535,8 @@
      *
      * @param time elapsed real-time of fix, in nanoseconds since system boot.
      */
-    public void setElapsedRealtimeNano(long time) {
-        mElapsedRealtimeNano = time;
+    public void setElapsedRealtimeNanos(long time) {
+        mElapsedRealtimeNanos = time;
     }
 
     /**
@@ -772,7 +772,7 @@
         if (mProvider == null) return false;
         if (!mHasAccuracy) return false;
         if (mTime == 0) return false;
-        if (mElapsedRealtimeNano == 0) return false;
+        if (mElapsedRealtimeNanos == 0) return false;
         return true;
     }
 
@@ -792,7 +792,7 @@
             mAccuracy = 100.0f;
         }
         if (mTime == 0) mTime = System.currentTimeMillis();
-        if (mElapsedRealtimeNano == 0) mElapsedRealtimeNano = SystemClock.elapsedRealtimeNano();
+        if (mElapsedRealtimeNanos == 0) mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
     }
 
     /**
@@ -832,11 +832,11 @@
         if (mTime == 0) {
             s.append(" t=?!?");
         }
-        if (mElapsedRealtimeNano == 0) {
+        if (mElapsedRealtimeNanos == 0) {
             s.append(" et=?!?");
         } else {
             s.append(" et=");
-            TimeUtils.formatDuration(mElapsedRealtimeNano / 1000000L, s);
+            TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s);
         }
         if (mHasAltitude) s.append(" alt=").append(mAltitude);
         if (mHasSpeed) s.append(" vel=").append(mSpeed);
@@ -860,7 +860,7 @@
             String provider = in.readString();
             Location l = new Location(provider);
             l.mTime = in.readLong();
-            l.mElapsedRealtimeNano = in.readLong();
+            l.mElapsedRealtimeNanos = in.readLong();
             l.mLatitude = in.readDouble();
             l.mLongitude = in.readDouble();
             l.mHasAltitude = in.readInt() != 0;
@@ -890,7 +890,7 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mProvider);
         parcel.writeLong(mTime);
-        parcel.writeLong(mElapsedRealtimeNano);
+        parcel.writeLong(mElapsedRealtimeNanos);
         parcel.writeDouble(mLatitude);
         parcel.writeDouble(mLongitude);
         parcel.writeInt(mHasAltitude ? 1 : 0);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 5b3c9e2..4ad8fd0 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1186,7 +1186,7 @@
      * Get the last known location.
      *
      * <p>This location could be very old so use
-     * {@link Location#getElapsedRealtimeNano} to calculate its age. It can
+     * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can
      * also return null if no previous location is available.
      *
      * <p>Always returns immediately.
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index b83521ae..2cf795d 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -215,7 +215,7 @@
     }
 
     private static double weighAge(Location loc) {
-        long ageSeconds = SystemClock.elapsedRealtimeNano() - loc.getElapsedRealtimeNano();
+        long ageSeconds = SystemClock.elapsedRealtimeNanos() - loc.getElapsedRealtimeNanos();
         ageSeconds /= 1000000000L;
         if (ageSeconds < 0) ageSeconds = 0;
         return Math.exp(-ageSeconds * AGE_DECAY_CONSTANT_S);
@@ -266,7 +266,7 @@
 
         // fused time - now
         fused.setTime(System.currentTimeMillis());
-        fused.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
+        fused.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
 
         // fuse altitude
         if (mGpsLocation.hasAltitude() && !mNetworkLocation.hasAltitude() &&
diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
index 89d4ef7..bd87238 100644
--- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java
+++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.service.dreams.Dream;
 import android.service.dreams.IDreamManager;
 import android.util.Slog;
 
@@ -45,7 +46,7 @@
             setResult(RESULT_OK, resultIntent);
         } else {
             IDreamManager somnambulist = IDreamManager.Stub.asInterface(
-                    ServiceManager.checkService("dreams"));
+                    ServiceManager.checkService(Dream.DREAM_SERVICE));
             if (somnambulist != null) {
                 try {
                     Slog.v("Somnambulator", "Dreaming by user request.");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e6aa632..d72632f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -45,6 +45,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.dreams.Dream;
 import android.service.dreams.IDreamManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -262,7 +263,7 @@
                 .getDefaultDisplay();
 
         mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.checkService("dreams"));
+                ServiceManager.checkService(Dream.DREAM_SERVICE));
 
         super.start(); // calls createAndAddWindows()
 
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 8ad5a91..4a8bf72 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,9 +16,6 @@
 
 package com.android.server;
 
-import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
-import static android.provider.Settings.Secure.SCREENSAVER_ENABLED;
-
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -27,16 +24,12 @@
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.dreams.IDreamManager;
 import android.util.Log;
 import android.util.Slog;
 
@@ -48,14 +41,10 @@
  */
 final class DockObserver extends UEventObserver {
     private static final String TAG = DockObserver.class.getSimpleName();
-    private static final boolean LOG = false;
 
     private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
     private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
 
-    private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
-    private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
     private static final int MSG_DOCK_STATE_CHANGED = 0;
 
     private final Object mLock = new Object();
@@ -66,11 +55,16 @@
     private boolean mSystemReady;
 
     private final Context mContext;
+    private final PowerManager mPowerManager;
+    private final PowerManager.WakeLock mWakeLock;
 
     public DockObserver(Context context) {
         mContext = context;
-        init();  // set initial status
 
+        mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+        init();  // set initial status
         startObserving(DOCK_UEVENT_MATCH);
     }
 
@@ -87,17 +81,9 @@
                     mPreviousDockState = mDockState;
                     mDockState = newState;
                     if (mSystemReady) {
-                        // Don't force screen on when undocking from the desk dock.
-                        // The change in power state will do this anyway.
-                        // FIXME - we should be configurable.
-                        if ((mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK
-                                && mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK
-                                && mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) ||
-                                mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                            PowerManager pm =
-                                    (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-                            pm.wakeUp(SystemClock.uptimeMillis());
-                        }
+                        // Wake up immediately when docked or undocked.
+                        mPowerManager.wakeUp(SystemClock.uptimeMillis());
+
                         updateLocked();
                     }
                 }
@@ -138,6 +124,7 @@
     }
 
     private void updateLocked() {
+        mWakeLock.acquire();
         mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
     }
 
@@ -145,8 +132,8 @@
         synchronized (mLock) {
             Slog.i(TAG, "Dock state changed: " + mDockState);
 
+            // Skip the dock intent if not yet provisioned.
             final ContentResolver cr = mContext.getContentResolver();
-
             if (Settings.Global.getInt(cr,
                     Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
                 Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
@@ -158,16 +145,8 @@
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
             intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
 
-            // Check if this is Bluetooth Dock
-            // TODO(BT): Get Dock address.
-            // String address = null;
-            // if (address != null) {
-            //    intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
-            //            BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
-            // }
-
-            // User feedback to confirm dock connection. Particularly
-            // useful for flaky contact pins...
+            // Play a sound to provide feedback to confirm dock connection.
+            // Particularly useful for flaky contact pins...
             if (Settings.Global.getInt(cr,
                     Settings.Global.DOCK_SOUNDS_ENABLED, 1) == 1) {
                 String whichSound = null;
@@ -204,44 +183,16 @@
                 }
             }
 
-            IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
-            if (mgr != null) {
-                // dreams feature enabled
-                boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED;
-                if (undocked) {
-                    try {
-                        if (mgr.isDreaming()) {
-                            mgr.awaken();
-                        }
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Unable to awaken!", e);
-                    }
-                } else {
-                    if (isScreenSaverEnabled(mContext) && isScreenSaverActivatedOnDock(mContext)) {
-                        try {
-                            mgr.dream();
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "Unable to dream!", e);
-                        }
-                    }
-                }
-            } else {
-                // dreams feature not enabled, send legacy intent
-                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-            }
+            // Send the dock event intent.
+            // There are many components in the system watching for this so as to
+            // adjust audio routing, screen orientation, etc.
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+
+            // Release the wake lock that was acquired when the message was posted.
+            mWakeLock.release();
         }
     }
 
-    private static boolean isScreenSaverEnabled(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED) != 0;
-    }
-
-    private static boolean isScreenSaverActivatedOnDock(Context context) {
-        return Settings.Secure.getInt(context.getContentResolver(),
-                SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK) != 0;
-    }
-
     private final Handler mHandler = new Handler(true /*async*/) {
         @Override
         public void handleMessage(Message msg) {
diff --git a/services/java/com/android/server/DreamController.java b/services/java/com/android/server/DreamController.java
deleted file mode 100644
index 498e581..0000000
--- a/services/java/com/android/server/DreamController.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.IBinder.DeathRecipient;
-import android.service.dreams.IDreamService;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-import com.android.internal.util.DumpUtils;
-
-import java.io.PrintWriter;
-import java.util.NoSuchElementException;
-
-/**
- * Internal controller for starting and stopping the current dream and managing related state.
- *
- * Assumes all operations (except {@link #dump}) are called from a single thread.
- */
-final class DreamController {
-    private static final boolean DEBUG = true;
-    private static final String TAG = DreamController.class.getSimpleName();
-
-    public interface Listener {
-        void onDreamStopped(boolean wasTest);
-    }
-
-    private final Context mContext;
-    private final IWindowManager mIWindowManager;
-    private final DeathRecipient mDeathRecipient;
-    private final ServiceConnection mServiceConnection;
-    private final Listener mListener;
-
-    private Handler mHandler;
-
-    private ComponentName mCurrentDreamComponent;
-    private IDreamService mCurrentDream;
-    private Binder mCurrentDreamToken;
-    private boolean mCurrentDreamIsTest;
-
-    public DreamController(Context context, DeathRecipient deathRecipient,
-            ServiceConnection serviceConnection, Listener listener) {
-        mContext = context;
-        mDeathRecipient = deathRecipient;
-        mServiceConnection = serviceConnection;
-        mListener = listener;
-        mIWindowManager = WindowManagerGlobal.getWindowManagerService();
-    }
-
-    public void setHandler(Handler handler) {
-        mHandler = handler;
-    }
-
-    public void dump(PrintWriter pw) {
-        if (mHandler== null || pw == null) {
-            return;
-        }
-        DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
-            @Override
-            public void dump(PrintWriter pw) {
-                pw.print("  component="); pw.println(mCurrentDreamComponent);
-                pw.print("  token="); pw.println(mCurrentDreamToken);
-                pw.print("  dream="); pw.println(mCurrentDream);
-            }
-        }, pw, 200);
-    }
-
-    public void start(ComponentName dream, boolean isTest) {
-        if (DEBUG) Slog.v(TAG, String.format("start(%s,%s)", dream, isTest));
-
-        if (mCurrentDreamComponent != null ) {
-            if (dream.equals(mCurrentDreamComponent) && isTest == mCurrentDreamIsTest) {
-                if (DEBUG) Slog.v(TAG, "Dream is already started: " + dream);
-                return;
-            }
-            // stop the current dream before starting a new one
-            stop();
-        }
-
-        mCurrentDreamComponent = dream;
-        mCurrentDreamIsTest = isTest;
-        mCurrentDreamToken = new Binder();
-
-        try {
-            if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
-                    + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
-            mIWindowManager.addWindowToken(mCurrentDreamToken,
-                    WindowManager.LayoutParams.TYPE_DREAM);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Unable to add window token.");
-            stop();
-            return;
-        }
-
-        Intent intent = new Intent(Intent.ACTION_MAIN)
-                .setComponent(mCurrentDreamComponent)
-                .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                .putExtra("android.dreams.TEST", mCurrentDreamIsTest);
-
-        if (!mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
-            Slog.w(TAG, "Unable to bind service");
-            stop();
-            return;
-        }
-        if (DEBUG) Slog.v(TAG, "Bound service");
-    }
-
-    public void attach(ComponentName name, IBinder dream) {
-        if (DEBUG) Slog.v(TAG, String.format("attach(%s,%s)", name, dream));
-        mCurrentDream = IDreamService.Stub.asInterface(dream);
-
-        boolean linked = linkDeathRecipient(dream);
-        if (!linked) {
-            stop();
-            return;
-        }
-
-        try {
-            if (DEBUG) Slog.v(TAG, "Attaching with token:" + mCurrentDreamToken);
-            mCurrentDream.attach(mCurrentDreamToken);
-        } catch (Throwable ex) {
-            Slog.w(TAG, "Unable to send window token to dream:" + ex);
-            stop();
-        }
-    }
-
-    public void stop() {
-        if (DEBUG) Slog.v(TAG, "stop()");
-
-        if (mCurrentDream != null) {
-            unlinkDeathRecipient(mCurrentDream.asBinder());
-
-            if (DEBUG) Slog.v(TAG, "Unbinding: " +  mCurrentDreamComponent + " service: " + mCurrentDream);
-            mContext.unbindService(mServiceConnection);
-        }
-        if (mCurrentDreamToken != null) {
-            removeWindowToken(mCurrentDreamToken);
-        }
-
-        final boolean wasTest = mCurrentDreamIsTest;
-        mCurrentDream = null;
-        mCurrentDreamToken = null;
-        mCurrentDreamComponent = null;
-        mCurrentDreamIsTest = false;
-
-        if (mListener != null && mHandler != null) {
-            mHandler.post(new Runnable(){
-                @Override
-                public void run() {
-                    mListener.onDreamStopped(wasTest);
-                }});
-        }
-    }
-
-    public void stopSelf(IBinder token) {
-        if (DEBUG) Slog.v(TAG, String.format("stopSelf(%s)", token));
-        if (token == null || token != mCurrentDreamToken) {
-            Slog.w(TAG, "Stop requested for non-current dream token: " + token);
-        } else {
-            stop();
-        }
-    }
-
-    private void removeWindowToken(IBinder token) {
-        if (DEBUG) Slog.v(TAG, "Removing window token: " + token);
-        try {
-            mIWindowManager.removeWindowToken(token);
-        } catch (Throwable e) {
-            Slog.w(TAG, "Error removing window token", e);
-        }
-    }
-
-    private boolean linkDeathRecipient(IBinder dream) {
-        if (DEBUG) Slog.v(TAG, "Linking death recipient");
-        try {
-            dream.linkToDeath(mDeathRecipient, 0);
-            return true;
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Unable to link death recipient",  e);
-            return false;
-        }
-    }
-
-    private void unlinkDeathRecipient(IBinder dream) {
-        if (DEBUG) Slog.v(TAG, "Unlinking death recipient");
-        try {
-            dream.unlinkToDeath(mDeathRecipient, 0);
-        } catch (NoSuchElementException e) {
-            // we tried
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/DreamManagerService.java b/services/java/com/android/server/DreamManagerService.java
deleted file mode 100644
index b02ea7f..0000000
--- a/services/java/com/android/server/DreamManagerService.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
-import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
-
-import android.app.ActivityManagerNative;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.dreams.Dream;
-import android.service.dreams.IDreamManager;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Service api for managing dreams.
- *
- * @hide
- */
-public final class DreamManagerService
-        extends IDreamManager.Stub
-        implements ServiceConnection {
-    private static final boolean DEBUG = true;
-    private static final String TAG = DreamManagerService.class.getSimpleName();
-
-    private static final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED)
-            .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-    private static final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED)
-            .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-
-    private final Object mLock = new Object();
-    private final DreamController mController;
-    private final DreamControllerHandler mHandler;
-    private final Context mContext;
-
-    private final CurrentUserManager mCurrentUserManager = new CurrentUserManager();
-
-    private final DeathRecipient mAwakenOnBinderDeath = new DeathRecipient() {
-        @Override
-        public void binderDied() {
-            if (DEBUG) Slog.v(TAG, "binderDied()");
-            awaken();
-        }
-    };
-
-    private final DreamController.Listener mControllerListener = new DreamController.Listener() {
-        @Override
-        public void onDreamStopped(boolean wasTest) {
-            synchronized(mLock) {
-                setDreamingLocked(false, wasTest);
-            }
-        }};
-
-    private boolean mIsDreaming;
-
-    public DreamManagerService(Context context) {
-        if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
-        mContext = context;
-        mController = new DreamController(context, mAwakenOnBinderDeath, this, mControllerListener);
-        mHandler = new DreamControllerHandler(mController);
-        mController.setHandler(mHandler);
-    }
-
-    public void systemReady() {
-        mCurrentUserManager.init(mContext);
-
-        if (DEBUG) Slog.v(TAG, "Ready to dream!");
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-        pw.println("Dreamland:");
-        mController.dump(pw);
-        mCurrentUserManager.dump(pw);
-    }
-
-    // begin IDreamManager api
-    @Override
-    public ComponentName[] getDreamComponents() {
-        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-        int userId = UserHandle.getCallingUserId();
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            return getDreamComponentsForUser(userId);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
-    public void setDreamComponents(ComponentName[] componentNames) {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-        int userId = UserHandle.getCallingUserId();
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                    SCREENSAVER_COMPONENTS,
-                    componentsToString(componentNames),
-                    userId);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
-    public ComponentName getDefaultDreamComponent() {
-        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-        int userId = UserHandle.getCallingUserId();
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                    SCREENSAVER_DEFAULT_COMPONENT,
-                    userId);
-            return name == null ? null : ComponentName.unflattenFromString(name);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-    }
-
-    @Override
-    public boolean isDreaming() {
-        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
-        return mIsDreaming;
-    }
-
-    @Override
-    public void dream() {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            if (DEBUG) Slog.v(TAG, "Dream now");
-            ComponentName[] dreams = getDreamComponentsForUser(mCurrentUserManager.getCurrentUserId());
-            ComponentName firstDream = dreams != null && dreams.length > 0 ? dreams[0] : null;
-            if (firstDream != null) {
-                mHandler.requestStart(firstDream, false /*isTest*/);
-                synchronized (mLock) {
-                    setDreamingLocked(true, false /*isTest*/);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
-    public void testDream(ComponentName dream) {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            if (DEBUG) Slog.v(TAG, "Test dream name=" + dream);
-            if (dream != null) {
-                mHandler.requestStart(dream, true /*isTest*/);
-                synchronized (mLock) {
-                    setDreamingLocked(true, true /*isTest*/);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-    }
-
-    @Override
-    public void awaken() {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            if (DEBUG) Slog.v(TAG, "Wake up");
-            mHandler.requestStop();
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
-    public void awakenSelf(IBinder token) {
-        // requires no permission, called by Dream from an arbitrary process
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            if (DEBUG) Slog.v(TAG, "Wake up from dream: " + token);
-            if (token != null) {
-                mHandler.requestStopSelf(token);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-    // end IDreamManager api
-
-    // begin ServiceConnection
-    @Override
-    public void onServiceConnected(ComponentName name, IBinder dream) {
-        if (DEBUG) Slog.v(TAG, "Service connected: " + name + " binder=" +
-                dream + " thread=" + Thread.currentThread().getId());
-        mHandler.requestAttach(name, dream);
-    }
-
-    @Override
-    public void onServiceDisconnected(ComponentName name) {
-        if (DEBUG) Slog.v(TAG, "Service disconnected: " + name);
-        // Only happens in exceptional circumstances, awaken just to be safe
-        awaken();
-    }
-    // end ServiceConnection
-
-    private void checkPermission(String permission) {
-        if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
-            throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
-                    + ", must have permission " + permission);
-        }
-    }
-
-    private void setDreamingLocked(boolean isDreaming, boolean isTest) {
-        boolean wasDreaming = mIsDreaming;
-        if (!isTest) {
-            if (!wasDreaming && isDreaming) {
-                if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STARTED");
-                mContext.sendBroadcast(mDreamingStartedIntent);
-            } else if (wasDreaming && !isDreaming) {
-                if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STOPPED");
-                mContext.sendBroadcast(mDreamingStoppedIntent);
-            }
-        }
-        mIsDreaming = isDreaming;
-    }
-
-    private ComponentName[] getDreamComponentsForUser(int userId) {
-        String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                SCREENSAVER_COMPONENTS,
-                userId);
-        return names == null ? null : componentsFromString(names);
-    }
-
-    private static String componentsToString(ComponentName[] componentNames) {
-        StringBuilder names = new StringBuilder();
-        if (componentNames != null) {
-            for (ComponentName componentName : componentNames) {
-                if (names.length() > 0) {
-                    names.append(',');
-                }
-                names.append(componentName.flattenToString());
-            }
-        }
-        return names.toString();
-    }
-
-    private static ComponentName[] componentsFromString(String names) {
-        String[] namesArray = names.split(",");
-        ComponentName[] componentNames = new ComponentName[namesArray.length];
-        for (int i = 0; i < namesArray.length; i++) {
-            componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
-        }
-        return componentNames;
-    }
-
-    /**
-     * Keeps track of the current user, since dream() uses the current user's configuration.
-     */
-    private static class CurrentUserManager {
-        private final Object mLock = new Object();
-        private int mCurrentUserId;
-
-        public void init(Context context) {
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
-            context.registerReceiver(new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    String action = intent.getAction();
-                    if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                        synchronized(mLock) {
-                            mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-                            if (DEBUG) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
-                        }
-                    }
-                }}, filter);
-            try {
-                synchronized (mLock) {
-                    mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
-            }
-        }
-
-        public void dump(PrintWriter pw) {
-            pw.print("  user="); pw.println(getCurrentUserId());
-        }
-
-        public int getCurrentUserId() {
-            synchronized(mLock) {
-                return mCurrentUserId;
-            }
-        }
-    }
-
-    /**
-     * Handler for asynchronous operations performed by the dream manager.
-     *
-     * Ensures operations to {@link DreamController} are single-threaded.
-     */
-    private static final class DreamControllerHandler extends Handler {
-        private final DreamController mController;
-        private final Runnable mStopRunnable = new Runnable() {
-            @Override
-            public void run() {
-                mController.stop();
-            }};
-
-        public DreamControllerHandler(DreamController controller) {
-            super(true /*async*/);
-            mController = controller;
-        }
-
-        public void requestStart(final ComponentName name, final boolean isTest) {
-            post(new Runnable(){
-                @Override
-                public void run() {
-                    mController.start(name, isTest);
-                }});
-        }
-
-        public void requestAttach(final ComponentName name, final IBinder dream) {
-            post(new Runnable(){
-                @Override
-                public void run() {
-                    mController.attach(name, dream);
-                }});
-        }
-
-        public void requestStopSelf(final IBinder token) {
-            post(new Runnable(){
-                @Override
-                public void run() {
-                    mController.stopSelf(token);
-                }});
-        }
-
-        public void requestStop() {
-            post(mStopRunnable);
-        }
-
-    }
-
-}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 578e602..a0c1552 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -17,17 +17,14 @@
 package com.android.server;
 
 import android.app.PendingIntent;
-import android.content.ContentQueryMap;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.database.Cursor;
 import android.location.Address;
 import android.location.Criteria;
 import android.location.GeocoderParams;
@@ -41,7 +38,6 @@
 import android.location.LocationManager;
 import android.location.LocationProvider;
 import android.location.LocationRequest;
-import android.net.ConnectivityManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -55,7 +51,6 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.provider.Settings.NameValueTable;
 import android.util.Log;
 import android.util.Slog;
 
@@ -80,8 +75,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Observable;
-import java.util.Observer;
 import java.util.Set;
 
 /**
@@ -1343,7 +1336,7 @@
 
         // Check whether sufficient time has passed
         long minTime = record.mRequest.getFastestInterval();
-        long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
+        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
         if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
             return false;
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eeab757..738e19b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,6 +38,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.server.search.SearchManagerService;
+import android.service.dreams.Dream;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -51,6 +52,7 @@
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.display.DisplayManagerService;
+import com.android.server.dreams.DreamManagerService;
 import com.android.server.input.InputManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
@@ -738,8 +740,8 @@
                 try {
                     Slog.i(TAG, "Dreams Service");
                     // Dreams (interactive idle-time views, a/k/a screen savers)
-                    dreamy = new DreamManagerService(context);
-                    ServiceManager.addService("dreams", dreamy);
+                    dreamy = new DreamManagerService(context, wmHandler);
+                    ServiceManager.addService(Dream.DREAM_SERVICE, dreamy);
                 } catch (Throwable e) {
                     reportWtf("starting DreamManagerService", e);
                 }
@@ -810,7 +812,7 @@
         context.getResources().updateConfiguration(config, metrics);
 
         try {
-            power.systemReady(twilight);
+            power.systemReady(twilight, dreamy);
         } catch (Throwable e) {
             reportWtf("making Power Manager Service ready", e);
         }
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/TwilightService.java
index a7bce54..154de1c 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/java/com/android/server/TwilightService.java
@@ -147,7 +147,7 @@
         }
 
         // if new location is older than the current one, the device hasn't moved.
-        if (to.getElapsedRealtimeNano() < from.getElapsedRealtimeNano()) {
+        if (to.getElapsedRealtimeNanos() < from.getElapsedRealtimeNanos()) {
             return false;
         }
 
@@ -428,8 +428,8 @@
                         mLocationManager.getLastKnownLocation(providers.next());
                 // pick the most recent location
                 if (location == null || (lastKnownLocation != null &&
-                        location.getElapsedRealtimeNano() <
-                        lastKnownLocation.getElapsedRealtimeNano())) {
+                        location.getElapsedRealtimeNanos() <
+                        lastKnownLocation.getElapsedRealtimeNanos())) {
                     location = lastKnownLocation;
                 }
             }
@@ -447,7 +447,7 @@
                 location.setLatitude(0);
                 location.setAccuracy(417000.0f);
                 location.setTime(System.currentTimeMillis());
-                location.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
+                location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
 
                 if (DEBUG) {
                     Slog.d(TAG, "Estimated location from timezone: " + location);
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 85a6e41..07e8f18 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IUiModeManager;
 import android.app.Notification;
@@ -39,6 +40,8 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.dreams.Dream;
+import android.service.dreams.IDreamManager;
 import android.util.Slog;
 
 import java.io.FileDescriptor;
@@ -56,6 +59,9 @@
     private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
     private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
 
+    private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
+    private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
+
     private final Context mContext;
     private final TwilightService mTwilightService;
     private final Handler mHandler = new Handler();
@@ -110,72 +116,10 @@
                 return;
             }
 
-            final int  enableFlags = intent.getIntExtra("enableFlags", 0);
-            final int  disableFlags = intent.getIntExtra("disableFlags", 0);
-
+            final int enableFlags = intent.getIntExtra("enableFlags", 0);
+            final int disableFlags = intent.getIntExtra("disableFlags", 0);
             synchronized (mLock) {
-                // Launch a dock activity
-                String category = null;
-                if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
-                    // Only launch car home when car mode is enabled and the caller
-                    // has asked us to switch to it.
-                    if (ENABLE_LAUNCH_CAR_DOCK_APP
-                            && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
-                        category = Intent.CATEGORY_CAR_DOCK;
-                    }
-                } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
-                    // Only launch car home when desk mode is enabled and the caller
-                    // has asked us to switch to it.  Currently re-using the car
-                    // mode flag since we don't have a formal API for "desk mode".
-                    if (ENABLE_LAUNCH_DESK_DOCK_APP
-                            && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
-                        category = Intent.CATEGORY_DESK_DOCK;
-                    }
-                } else {
-                    // Launch the standard home app if requested.
-                    if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
-                        category = Intent.CATEGORY_HOME;
-                    }
-                }
-
-                if (LOG) {
-                    Slog.v(TAG, String.format(
-                        "Handling broadcast result for action %s: enable=0x%08x disable=0x%08x category=%s",
-                        intent.getAction(), enableFlags, disableFlags, category));
-                }
-
-                if (category != null) {
-                    // This is the new activity that will serve as home while
-                    // we are in care mode.
-                    Intent homeIntent = buildHomeIntent(category);
-
-                    // Now we are going to be careful about switching the
-                    // configuration and starting the activity -- we need to
-                    // do this in a specific order under control of the
-                    // activity manager, to do it cleanly.  So compute the
-                    // new config, but don't set it yet, and let the
-                    // activity manager take care of both the start and config
-                    // change.
-                    Configuration newConfig = null;
-                    if (mHoldingConfiguration) {
-                        mHoldingConfiguration = false;
-                        updateConfigurationLocked(false);
-                        newConfig = mConfiguration;
-                    }
-                    try {
-                        ActivityManagerNative.getDefault().startActivityWithConfig(
-                                null, homeIntent, null, null, null, 0, 0,
-                                newConfig, null, UserHandle.USER_CURRENT);
-                        mHoldingConfiguration = false;
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, e.getCause());
-                    }
-                }
-
-                if (mHoldingConfiguration) {
-                    mHoldingConfiguration = false;
-                    updateConfigurationLocked(true);
-                }
+                updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags);
             }
         }
     };
@@ -335,9 +279,8 @@
         }
     }
 
-    final void updateConfigurationLocked(boolean sendIt) {
-        int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION
-                : mDefaultUiModeType;
+    final void updateConfigurationLocked() {
+        int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION : mDefaultUiModeType;
         if (mCarModeEnabled) {
             uiMode = Configuration.UI_MODE_TYPE_CAR;
         } else if (isDeskDockState(mDockState)) {
@@ -365,17 +308,19 @@
         }
 
         mCurUiMode = uiMode;
-
-        if (!mHoldingConfiguration && uiMode != mSetUiMode) {
-            mSetUiMode = uiMode;
+        if (!mHoldingConfiguration) {
             mConfiguration.uiMode = uiMode;
+        }
+    }
 
-            if (sendIt) {
-                try {
-                    ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failure communicating with activity manager", e);
-                }
+    final void sendConfigurationLocked() {
+        if (mSetUiMode != mConfiguration.uiMode) {
+            mSetUiMode = mConfiguration.uiMode;
+
+            try {
+                ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failure communicating with activity manager", e);
             }
         }
     }
@@ -434,43 +379,38 @@
                 intent.putExtra("disableFlags", disableFlags);
                 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
                         mResultReceiver, null, Activity.RESULT_OK, null, null);
+
                 // Attempting to make this transition a little more clean, we are going
                 // to hold off on doing a configuration change until we have finished
                 // the broadcast and started the home activity.
                 mHoldingConfiguration = true;
+                updateConfigurationLocked();
             } else {
-                Intent homeIntent = null;
+                String category = null;
                 if (mCarModeEnabled) {
                     if (ENABLE_LAUNCH_CAR_DOCK_APP
-                            && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
-                        homeIntent = buildHomeIntent(Intent.CATEGORY_CAR_DOCK);
+                            && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+                        category = Intent.CATEGORY_CAR_DOCK;
                     }
                 } else if (isDeskDockState(mDockState)) {
                     if (ENABLE_LAUNCH_DESK_DOCK_APP
-                            && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
-                        homeIntent = buildHomeIntent(Intent.CATEGORY_DESK_DOCK);
+                            && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+                        category = Intent.CATEGORY_DESK_DOCK;
                     }
                 } else {
-                    if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
-                        homeIntent = buildHomeIntent(Intent.CATEGORY_HOME);
+                    if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+                        category = Intent.CATEGORY_HOME;
                     }
                 }
 
                 if (LOG) {
                     Slog.v(TAG, "updateLocked: null action, mDockState="
-                            + mDockState +", firing homeIntent: " + homeIntent);
+                            + mDockState +", category=" + category);
                 }
 
-                if (homeIntent != null) {
-                    try {
-                        mContext.startActivityAsUser(homeIntent, UserHandle.CURRENT);
-                    } catch (ActivityNotFoundException e) {
-                    }
-                }
+                sendConfigurationAndStartDreamOrDockAppLocked(category);
             }
 
-            updateConfigurationLocked(true);
-
             // keep screen on when charging and in car mode
             boolean keepScreenOn = mCharging &&
                     ((mCarModeEnabled && mCarModeKeepsScreenOn) ||
@@ -487,6 +427,100 @@
         }
     }
 
+    private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) {
+        // Launch a dock activity
+        String category = null;
+        if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) {
+            // Only launch car home when car mode is enabled and the caller
+            // has asked us to switch to it.
+            if (ENABLE_LAUNCH_CAR_DOCK_APP
+                    && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+                category = Intent.CATEGORY_CAR_DOCK;
+            }
+        } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) {
+            // Only launch car home when desk mode is enabled and the caller
+            // has asked us to switch to it.  Currently re-using the car
+            // mode flag since we don't have a formal API for "desk mode".
+            if (ENABLE_LAUNCH_DESK_DOCK_APP
+                    && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+                category = Intent.CATEGORY_DESK_DOCK;
+            }
+        } else {
+            // Launch the standard home app if requested.
+            if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+                category = Intent.CATEGORY_HOME;
+            }
+        }
+
+        if (LOG) {
+            Slog.v(TAG, String.format(
+                "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, "
+                    + "category=%s",
+                action, enableFlags, disableFlags, category));
+        }
+
+        sendConfigurationAndStartDreamOrDockAppLocked(category);
+    }
+
+    private void sendConfigurationAndStartDreamOrDockAppLocked(String category) {
+        // Update the configuration but don't send it yet.
+        mHoldingConfiguration = false;
+        updateConfigurationLocked();
+
+        // Start the dock app, if there is one.
+        boolean dockAppStarted = false;
+        if (category != null) {
+            // Now we are going to be careful about switching the
+            // configuration and starting the activity -- we need to
+            // do this in a specific order under control of the
+            // activity manager, to do it cleanly.  So compute the
+            // new config, but don't set it yet, and let the
+            // activity manager take care of both the start and config
+            // change.
+            Intent homeIntent = buildHomeIntent(category);
+            try {
+                int result = ActivityManagerNative.getDefault().startActivityWithConfig(
+                        null, homeIntent, null, null, null, 0, 0,
+                        mConfiguration, null, UserHandle.USER_CURRENT);
+                if (result >= ActivityManager.START_SUCCESS) {
+                    dockAppStarted = true;
+                } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
+                    Slog.e(TAG, "Could not start dock app: " + homeIntent
+                            + ", startActivityWithConfig result " + result);
+                }
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
+            }
+        }
+
+        // Send the new configuration.
+        sendConfigurationLocked();
+
+        // If we did not start a dock app, then start dreaming if supported.
+        if (!dockAppStarted && isScreenSaverEnabled() && isScreenSaverActivatedOnDock()) {
+            Slog.i(TAG, "Activating dream while docked.");
+            try {
+                IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
+                        ServiceManager.getService(Dream.DREAM_SERVICE));
+                dreamManagerService.dream();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Could not start dream when docked.", ex);
+            }
+        }
+    }
+
+    private boolean isScreenSaverEnabled() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
+                UserHandle.USER_CURRENT) != 0;
+    }
+
+    private boolean isScreenSaverActivatedOnDock() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+                DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
+    }
+
     private void adjustStatusBarCarModeLocked() {
         if (mStatusBarManager == null) {
             mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/java/com/android/server/dreams/DreamController.java
new file mode 100644
index 0000000..81c80187
--- /dev/null
+++ b/services/java/com/android/server/dreams/DreamController.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.dreams;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.service.dreams.Dream;
+import android.service.dreams.IDreamService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.io.PrintWriter;
+import java.util.NoSuchElementException;
+
+/**
+ * Internal controller for starting and stopping the current dream and managing related state.
+ *
+ * Assumes all operations are called from the dream handler thread.
+ */
+final class DreamController {
+    private static final String TAG = "DreamController";
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Listener mListener;
+    private final IWindowManager mIWindowManager;
+
+    private final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED)
+            .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+    private final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED)
+            .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+    private DreamRecord mCurrentDream;
+
+    public DreamController(Context context, Handler handler, Listener listener) {
+        mContext = context;
+        mHandler = handler;
+        mListener = listener;
+        mIWindowManager = WindowManagerGlobal.getWindowManagerService();
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("Dreamland:");
+        if (mCurrentDream != null) {
+            pw.println("  mCurrentDream:");
+            pw.println("    mToken=" + mCurrentDream.mToken);
+            pw.println("    mName=" + mCurrentDream.mName);
+            pw.println("    mIsTest=" + mCurrentDream.mIsTest);
+            pw.println("    mUserId=" + mCurrentDream.mUserId);
+            pw.println("    mBound=" + mCurrentDream.mBound);
+            pw.println("    mService=" + mCurrentDream.mService);
+            pw.println("    mSentStartBroadcast=" + mCurrentDream.mSentStartBroadcast);
+        } else {
+            pw.println("  mCurrentDream: null");
+        }
+    }
+
+    public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+        stopDream();
+
+        Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+
+        mCurrentDream = new DreamRecord(token, name, isTest, userId);
+
+        try {
+            mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Unable to add window token for dream.", ex);
+            stopDream();
+            return;
+        }
+
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Dream.CATEGORY_DREAM);
+        intent.setComponent(name);
+        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        try {
+            if (!mContext.bindService(intent, mCurrentDream,
+                    Context.BIND_AUTO_CREATE, userId)) {
+                Slog.e(TAG, "Unable to bind dream service: " + intent);
+                stopDream();
+                return;
+            }
+        } catch (SecurityException ex) {
+            Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
+            stopDream();
+            return;
+        }
+
+        mCurrentDream.mBound = true;
+    }
+
+    public void stopDream() {
+        if (mCurrentDream == null) {
+            return;
+        }
+
+        final DreamRecord oldDream = mCurrentDream;
+        mCurrentDream = null;
+        Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
+                + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+
+        if (oldDream.mSentStartBroadcast) {
+            mContext.sendBroadcast(mDreamingStoppedIntent);
+        }
+
+        if (oldDream.mService != null) {
+            // TODO: It would be nice to tell the dream that it's being stopped so that
+            // it can shut down nicely before we yank its window token out from under it.
+            try {
+                oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
+            } catch (NoSuchElementException ex) {
+                // don't care
+            }
+            oldDream.mService = null;
+        }
+
+        if (oldDream.mBound) {
+            mContext.unbindService(oldDream);
+        }
+
+        try {
+            mIWindowManager.removeWindowToken(oldDream.mToken);
+        } catch (RemoteException ex) {
+            Slog.w(TAG, "Error removing window token for dream.", ex);
+        }
+
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mListener.onDreamStopped(oldDream.mToken);
+            }
+        });
+    }
+
+    private void attach(IDreamService service) {
+        try {
+            service.asBinder().linkToDeath(mCurrentDream, 0);
+            service.attach(mCurrentDream.mToken);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "The dream service died unexpectedly.", ex);
+            stopDream();
+            return;
+        }
+
+        mCurrentDream.mService = service;
+
+        if (!mCurrentDream.mIsTest) {
+            mContext.sendBroadcast(mDreamingStartedIntent);
+            mCurrentDream.mSentStartBroadcast = true;
+        }
+    }
+
+    /**
+     * Callback interface to be implemented by the {@link DreamManagerService}.
+     */
+    public interface Listener {
+        void onDreamStopped(Binder token);
+    }
+
+    private final class DreamRecord implements DeathRecipient, ServiceConnection {
+        public final Binder mToken;
+        public final ComponentName mName;
+        public final boolean mIsTest;
+        public final int mUserId;
+
+        public boolean mBound;
+        public IDreamService mService;
+        public boolean mSentStartBroadcast;
+
+        public DreamRecord(Binder token, ComponentName name,
+                boolean isTest, int userId) {
+            mToken = token;
+            mName = name;
+            mIsTest = isTest;
+            mUserId  = userId;
+        }
+
+        // May be called on any thread.
+        @Override
+        public void binderDied() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mService = null;
+                    if (mCurrentDream == DreamRecord.this) {
+                        stopDream();
+                    }
+                }
+            });
+        }
+
+        // May be called on any thread.
+        @Override
+        public void onServiceConnected(ComponentName name, final IBinder service) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (mCurrentDream == DreamRecord.this && mService == null) {
+                        attach(IDreamService.Stub.asInterface(service));
+                    }
+                }
+            });
+        }
+
+        // May be called on any thread.
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mService = null;
+                    if (mCurrentDream == DreamRecord.this) {
+                        stopDream();
+                    }
+                }
+            });
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
new file mode 100644
index 0000000..1f40176
--- /dev/null
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.dreams;
+
+import com.android.internal.util.DumpUtils;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.IDreamManager;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import libcore.util.Objects;
+
+/**
+ * Service api for managing dreams.
+ *
+ * @hide
+ */
+public final class DreamManagerService extends IDreamManager.Stub {
+    private static final boolean DEBUG = true;
+    private static final String TAG = "DreamManagerService";
+
+    private final Object mLock = new Object();
+
+    private final Context mContext;
+    private final DreamHandler mHandler;
+    private final DreamController mController;
+    private final PowerManager mPowerManager;
+
+    private Binder mCurrentDreamToken;
+    private ComponentName mCurrentDreamName;
+    private int mCurrentDreamUserId;
+    private boolean mCurrentDreamIsTest;
+
+    public DreamManagerService(Context context, Handler mainHandler) {
+        mContext = context;
+        mHandler = new DreamHandler(mainHandler.getLooper());
+        mController = new DreamController(context, mHandler, mControllerListener);
+
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+    }
+
+    public void systemReady() {
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                synchronized (mLock) {
+                    stopDreamLocked();
+                }
+            }
+        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+        pw.println("DREAM MANAGER (dumpsys dreams)");
+        pw.println();
+
+        pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
+        pw.println("mCurrentDreamName=" + mCurrentDreamName);
+        pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
+        pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+        pw.println();
+
+        DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
+            @Override
+            public void dump(PrintWriter pw) {
+                mController.dump(pw);
+            }
+        }, pw, 200);
+    }
+
+    @Override // Binder call
+    public ComponentName[] getDreamComponents() {
+        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+        final int userId = UserHandle.getCallingUserId();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            return getDreamComponentsForUser(userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void setDreamComponents(ComponentName[] componentNames) {
+        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+        final int userId = UserHandle.getCallingUserId();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.SCREENSAVER_COMPONENTS,
+                    componentsToString(componentNames),
+                    userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public ComponentName getDefaultDreamComponent() {
+        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+        final int userId = UserHandle.getCallingUserId();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+                    userId);
+            return name == null ? null : ComponentName.unflattenFromString(name);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public boolean isDreaming() {
+        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+        synchronized (mLock) {
+            return mCurrentDreamToken != null && !mCurrentDreamIsTest;
+        }
+    }
+
+    @Override // Binder call
+    public void dream() {
+        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            // Ask the power manager to nap.  It will eventually call back into
+            // startDream() if/when it is appropriate to start dreaming.
+            // Because napping could cause the screen to turn off immediately if the dream
+            // cannot be started, we keep one eye open and gently poke user activity.
+            long time = SystemClock.uptimeMillis();
+            mPowerManager.userActivity(time, true /*noChangeLights*/);
+            mPowerManager.nap(time);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void testDream(ComponentName dream) {
+        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+        if (dream == null) {
+            throw new IllegalArgumentException("dream must not be null");
+        }
+
+        final int callingUserId = UserHandle.getCallingUserId();
+        final int currentUserId = ActivityManager.getCurrentUser();
+        if (callingUserId != currentUserId) {
+            // This check is inherently prone to races but at least it's something.
+            Slog.w(TAG, "Aborted attempt to start a test dream while a different "
+                    + " user is active: callingUserId=" + callingUserId
+                    + ", currentUserId=" + currentUserId);
+            return;
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                startDreamLocked(dream, true /*isTest*/, callingUserId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void awaken() {
+        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            // Treat an explicit request to awaken as user activity so that the
+            // device doesn't immediately go to sleep if the timeout expired,
+            // for example when being undocked.
+            long time = SystemClock.uptimeMillis();
+            mPowerManager.userActivity(time, false /*noChangeLights*/);
+            stopDream();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void finishSelf(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 {
+            if (DEBUG) {
+                Slog.d(TAG, "Dream finished: " + token);
+            }
+
+            // Note that a dream finishing and self-terminating is not
+            // itself considered user activity.  If the dream is ending because
+            // the user interacted with the device then user activity will already
+            // have been poked so the device will stay awake a bit longer.
+            // If the dream is ending on its own for other reasons and no wake
+            // locks are held and the user activity timeout has expired then the
+            // device may simply go to sleep.
+            synchronized (mLock) {
+                if (mCurrentDreamToken == token) {
+                    stopDreamLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Called by the power manager to start a dream.
+     */
+    public void startDream() {
+        int userId = ActivityManager.getCurrentUser();
+        ComponentName dream = chooseDreamForUser(userId);
+        if (dream != null) {
+            synchronized (mLock) {
+                startDreamLocked(dream, false /*isTest*/, userId);
+            }
+        }
+    }
+
+    /**
+     * Called by the power manager to stop a dream.
+     */
+    public void stopDream() {
+        synchronized (mLock) {
+            stopDreamLocked();
+        }
+    }
+
+    private ComponentName chooseDreamForUser(int userId) {
+        ComponentName[] dreams = getDreamComponentsForUser(userId);
+        return dreams != null && dreams.length != 0 ? dreams[0] : null;
+    }
+
+    private ComponentName[] getDreamComponentsForUser(int userId) {
+        String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_COMPONENTS,
+                userId);
+        return names == null ? null : componentsFromString(names);
+    }
+
+    private void startDreamLocked(final ComponentName name,
+            final boolean isTest, final int userId) {
+        if (Objects.equal(mCurrentDreamName, name)
+                && mCurrentDreamIsTest == isTest
+                && mCurrentDreamUserId == userId) {
+            return;
+        }
+
+        stopDreamLocked();
+
+        Slog.i(TAG, "Entering dreamland.");
+
+        final Binder newToken = new Binder();
+        mCurrentDreamToken = newToken;
+        mCurrentDreamName = name;
+        mCurrentDreamIsTest = isTest;
+        mCurrentDreamUserId = userId;
+
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mController.startDream(newToken, name, isTest, userId);
+            }
+        });
+    }
+
+    private void stopDreamLocked() {
+        if (mCurrentDreamToken != null) {
+            Slog.i(TAG, "Leaving dreamland.");
+
+            cleanupDreamLocked();
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mController.stopDream();
+                }
+            });
+        }
+    }
+
+    private void cleanupDreamLocked() {
+        mCurrentDreamToken = null;
+        mCurrentDreamName = null;
+        mCurrentDreamIsTest = false;
+        mCurrentDreamUserId = 0;
+    }
+
+    private void checkPermission(String permission) {
+        if (mContext.checkCallingOrSelfPermission(permission)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+                    + ", must have permission " + permission);
+        }
+    }
+
+    private static String componentsToString(ComponentName[] componentNames) {
+        StringBuilder names = new StringBuilder();
+        if (componentNames != null) {
+            for (ComponentName componentName : componentNames) {
+                if (names.length() > 0) {
+                    names.append(',');
+                }
+                names.append(componentName.flattenToString());
+            }
+        }
+        return names.toString();
+    }
+
+    private static ComponentName[] componentsFromString(String names) {
+        String[] namesArray = names.split(",");
+        ComponentName[] componentNames = new ComponentName[namesArray.length];
+        for (int i = 0; i < namesArray.length; i++) {
+            componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+        }
+        return componentNames;
+    }
+
+    private final DreamController.Listener mControllerListener = new DreamController.Listener() {
+        @Override
+        public void onDreamStopped(Binder token) {
+            synchronized (mLock) {
+                if (mCurrentDreamToken == token) {
+                    cleanupDreamLocked();
+                }
+            }
+        }
+    };
+
+    /**
+     * Handler for asynchronous operations performed by the dream manager.
+     * Ensures operations to {@link DreamController} are single-threaded.
+     */
+    private final class DreamHandler extends Handler {
+        public DreamHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+    }
+}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 28870a2..84adb83 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -1029,7 +1029,7 @@
                 mLocation.setTime(timestamp);
                 // It would be nice to push the elapsed real-time timestamp
                 // further down the stack, but this is still useful
-                mLocation.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
+                mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
             }
             if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
                 mLocation.setAltitude(altitude);
diff --git a/services/java/com/android/server/location/LocationBasedCountryDetector.java b/services/java/com/android/server/location/LocationBasedCountryDetector.java
index 38871d78..03db621 100755
--- a/services/java/com/android/server/location/LocationBasedCountryDetector.java
+++ b/services/java/com/android/server/location/LocationBasedCountryDetector.java
@@ -115,8 +115,8 @@
             Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider);
             if (lastKnownLocation != null) {
                 if (bestLocation == null ||
-                        bestLocation.getElapsedRealtimeNano() <
-                        lastKnownLocation.getElapsedRealtimeNano()) {
+                        bestLocation.getElapsedRealtimeNanos() <
+                        lastKnownLocation.getElapsedRealtimeNanos()) {
                     bestLocation = lastKnownLocation;
                 }
             }
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 030eb5e..ad138e8 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -24,6 +24,7 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.display.DisplayManagerService;
+import com.android.server.dreams.DreamManagerService;
 
 import android.Manifest;
 import android.content.BroadcastReceiver;
@@ -46,13 +47,11 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.service.dreams.Dream;
-import android.service.dreams.IDreamManager;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -100,14 +99,12 @@
     private static final int DIRTY_STAY_ON = 1 << 7;
     // Dirty bit: battery state changed
     private static final int DIRTY_BATTERY_STATE = 1 << 8;
-    // Dirty bit: dream ended
-    private static final int DIRTY_DREAM_ENDED = 1 << 9;
 
     // 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.
     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.
+    // When the user activity timeout expires, the device may start napping 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
@@ -149,7 +146,7 @@
     private Notifier mNotifier;
     private DisplayPowerController mDisplayPowerController;
     private SettingsObserver mSettingsObserver;
-    private IDreamManager mDreamManager;
+    private DreamManagerService mDreamManager;
     private LightsService.Light mAttentionLight;
 
     private final Object mLock = new Object();
@@ -335,9 +332,10 @@
         }
     }
 
-    public void systemReady(TwilightService twilight) {
+    public void systemReady(TwilightService twilight, DreamManagerService dreamManager) {
         synchronized (mLock) {
             mSystemReady = true;
+            mDreamManager = dreamManager;
 
             PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
             mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
@@ -365,10 +363,7 @@
             mContext.registerReceiver(new BootCompletedReceiver(), filter, null, mHandler);
 
             filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_DOCK_EVENT);
-            mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
-
-            filter = new IntentFilter();
+            filter.addAction(Dream.ACTION_DREAMING_STARTED);
             filter.addAction(Dream.ACTION_DREAMING_STOPPED);
             mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
 
@@ -887,6 +882,47 @@
         return true;
     }
 
+    @Override // Binder call
+    public void nap(long eventTime) {
+        if (eventTime > SystemClock.uptimeMillis()) {
+            throw new IllegalArgumentException("event time must not be in the future");
+        }
+
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            napInternal(eventTime);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void napInternal(long eventTime) {
+        synchronized (mLock) {
+            if (napNoUpdateLocked(eventTime)) {
+                updatePowerStateLocked();
+            }
+        }
+    }
+
+    private boolean napNoUpdateLocked(long eventTime) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime);
+        }
+
+        if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
+                || !mBootCompleted || !mSystemReady) {
+            return false;
+        }
+
+        Slog.i(TAG, "Nap time...");
+
+        mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_NAPPING;
+        return true;
+    }
+
     /**
      * Updates the global power state based on dirty bits recorded in mDirty.
      *
@@ -1143,11 +1179,15 @@
                 | DIRTY_WAKEFULNESS | DIRTY_STAY_ON)) != 0) {
             if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                 if (DEBUG_SPEW) {
-                    Slog.d(TAG, "updateWakefulnessLocked: Nap time...");
+                    Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
                 }
-                mWakefulness = WAKEFULNESS_NAPPING;
-                mDirty |= DIRTY_WAKEFULNESS;
-                changed = true;
+                final long time = SystemClock.uptimeMillis();
+                if (mDreamsActivateOnSleepSetting) {
+                    changed = napNoUpdateLocked(time);
+                } else {
+                    changed = goToSleepNoUpdateLocked(time,
+                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+                }
             }
         }
         return changed;
@@ -1172,8 +1212,7 @@
                 | DIRTY_SETTINGS
                 | DIRTY_IS_POWERED
                 | DIRTY_STAY_ON
-                | DIRTY_BATTERY_STATE
-                | DIRTY_DREAM_ENDED)) != 0) {
+                | DIRTY_BATTERY_STATE)) != 0) {
             scheduleSandmanLocked();
         }
     }
@@ -1210,32 +1249,15 @@
             }
         }
 
-        // Get the dream manager, if needed.
-        if (startDreaming && mDreamManager == null) {
-            mDreamManager = IDreamManager.Stub.asInterface(
-                    ServiceManager.checkService("dreams"));
-            if (mDreamManager == null) {
-                Slog.w(TAG, "Unable to find IDreamManager.");
-            }
-        }
-
         // 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;
         if (mDreamManager != null) {
-            try {
-                isDreaming = mDreamManager.isDreaming();
-                if (startDreaming && !isDreaming) {
-                    Slog.i(TAG, "Entering dreamland.");
-                    mDreamManager.dream();
-                    isDreaming = mDreamManager.isDreaming();
-                    if (!isDreaming) {
-                        Slog.i(TAG, "Could not enter dreamland.  Sleep will be dreamless.");
-                    }
-                }
-            } catch (RemoteException ex) {
+            if (startDreaming) {
+                mDreamManager.startDream();
             }
+            isDreaming = mDreamManager.isDreaming();
         }
 
         // Update dream state.
@@ -1255,18 +1277,6 @@
             if (!continueDreaming) {
                 handleDreamFinishedLocked();
             }
-
-            // In addition to listening for the intent, poll the sandman periodically to detect
-            // when the dream has ended (as a watchdog only, ensuring our state is always correct).
-            if (mWakefulness == WAKEFULNESS_DREAMING
-                    || mWakefulness == WAKEFULNESS_NAPPING) {
-                if (!mSandmanScheduled) {
-                    mSandmanScheduled = true;
-                    Message msg = mHandler.obtainMessage(MSG_SANDMAN);
-                    msg.setAsynchronous(true);
-                    mHandler.sendMessageDelayed(msg, 5000);
-                }
-            }
         }
 
         // Stop dreaming if needed.
@@ -1274,26 +1284,22 @@
         // If so, then the power manager will have posted another message to the handler
         // to take care of it later.
         if (mDreamManager != null) {
-            try {
-                if (!continueDreaming && isDreaming) {
-                    Slog.i(TAG, "Leaving dreamland.");
-                    mDreamManager.awaken();
-                }
-            } catch (RemoteException ex) {
+            if (!continueDreaming) {
+                mDreamManager.stopDream();
             }
         }
     }
 
     /**
      * Returns true if the device is allowed to dream in its current state,
-     * assuming there has been no recent user activity and no wake locks are held.
+     * assuming that there was either an explicit request to nap or the user activity
+     * timeout expired and no wake locks are held.
      */
     private boolean canDreamLocked() {
         return mIsPowered
                 && mDreamsSupportedConfig
                 && mDreamsEnabledSetting
-                && mDreamsActivateOnSleepSetting
-                && !mBatteryService.isBatteryLow();
+                && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
     }
 
     /**
@@ -1313,7 +1319,6 @@
         }
     }
 
-
     /**
      * Updates the display power state asynchronously.
      * When the update is finished, mDisplayReady will be set to true.  The display
@@ -1494,15 +1499,6 @@
         updatePowerStateLocked();
     }
 
-    private void handleDockStateChangedLocked(int dockState) {
-        // TODO
-    }
-
-    private void handleDreamEndedLocked() {
-        mDirty |= DIRTY_DREAM_ENDED;
-        updatePowerStateLocked();
-    }
-
     /**
      * Reboot the device immediately, passing 'reason' (may be null)
      * to the underlying __reboot system call.  Should not return.
@@ -1957,22 +1953,11 @@
         }
     }
 
-    private final class DockReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            synchronized (mLock) {
-                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
-                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
-                handleDockStateChangedLocked(dockState);
-            }
-        }
-    }
-
     private final class DreamReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             synchronized (mLock) {
-                handleDreamEndedLocked();
+                scheduleSandmanLocked();
             }
         }
     }
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
index 4715d6e..f0a2b92 100644
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
+++ b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
@@ -54,6 +54,10 @@
                 android:id="@+id/filterselection"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"/>
+            <Spinner
+                android:id="@+id/spinner1"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
             <TextView
                 android:id="@+id/slider1Text"
                 android:layout_width="match_parent"
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java
new file mode 100644
index 0000000..2920824
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image;
+
+import java.lang.Math;
+import java.lang.Short;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.ScriptGroup;
+import android.renderscript.ScriptIntrinsicBlend;
+import android.renderscript.Type;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.Spinner;
+
+public class Blend extends TestBase {
+    private ScriptIntrinsicBlend mBlend;
+    private ScriptC_blend mBlendHelper;
+    private short image1Alpha = 128;
+    private short image2Alpha = 128;
+
+    String mIntrinsicNames[];
+
+    private Allocation image1;
+    private Allocation image2;
+    private int currentIntrinsic = 0;
+
+    private AdapterView.OnItemSelectedListener mIntrinsicSpinnerListener =
+            new AdapterView.OnItemSelectedListener() {
+                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+                    currentIntrinsic = pos;
+                    runTest();
+                    act.updateDisplay();
+                }
+
+                public void onNothingSelected(AdapterView parent) {
+
+                }
+            };
+
+    public void createTest(android.content.res.Resources res) {
+        mBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS));
+        mBlendHelper = new ScriptC_blend(mRS);
+        mBlendHelper.set_alpha((short)128);
+
+        image1 = Allocation.createTyped(mRS, mInPixelsAllocation.getType());
+        image2 = Allocation.createTyped(mRS, mInPixelsAllocation2.getType());
+
+        mIntrinsicNames = new String[14];
+        mIntrinsicNames[0] = "Source";
+        mIntrinsicNames[1] = "Destination";
+        mIntrinsicNames[2] = "Source Over";
+        mIntrinsicNames[3] = "Destination Over";
+        mIntrinsicNames[4] = "Source In";
+        mIntrinsicNames[5] = "Destination In";
+        mIntrinsicNames[6] = "Source Out";
+        mIntrinsicNames[7] = "Destination Out";
+        mIntrinsicNames[8] = "Source Atop";
+        mIntrinsicNames[9] = "Destination Atop";
+        mIntrinsicNames[10] = "XOR";
+        mIntrinsicNames[11] = "Add";
+        mIntrinsicNames[12] = "Subtract";
+        mIntrinsicNames[13] = "Multiply";
+    }
+
+    public boolean onSpinner1Setup(Spinner s) {
+        s.setAdapter(new ArrayAdapter<String>(
+            act, R.layout.spinner_layout, mIntrinsicNames));
+        s.setOnItemSelectedListener(mIntrinsicSpinnerListener);
+        return true;
+    }
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Image 1 Alpha");
+        b.setMax(255);
+        b.setProgress(image1Alpha);
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        image1Alpha = (short)progress;
+    }
+
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        t.setText("Image 2 Alpha");
+        b.setMax(255);
+        b.setProgress(image2Alpha);
+        return true;
+    }
+
+    public void onBar2Changed(int progress) {
+        image2Alpha = (short)progress;
+    }
+
+    public void runTest() {
+        image1.copy2DRangeFrom(0, 0, mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), mInPixelsAllocation, 0, 0);
+        image2.copy2DRangeFrom(0, 0, mInPixelsAllocation2.getType().getX(), mInPixelsAllocation2.getType().getY(), mInPixelsAllocation2, 0, 0);
+
+        mBlendHelper.set_alpha(image1Alpha);
+        mBlendHelper.forEach_setImageAlpha(image1);
+
+        mBlendHelper.set_alpha(image2Alpha);
+        mBlendHelper.forEach_setImageAlpha(image2);
+
+        switch (currentIntrinsic) {
+        case 0:
+            mBlend.forEachSrc(image1, image2);
+            break;
+        case 1:
+            mBlend.forEachDst(image1, image2);
+            break;
+        case 2:
+            mBlend.forEachSrcOver(image1, image2);
+            break;
+        case 3:
+            mBlend.forEachDstOver(image1, image2);
+            break;
+        case 4:
+            mBlend.forEachSrcIn(image1, image2);
+            break;
+        case 5:
+            mBlend.forEachDstIn(image1, image2);
+            break;
+        case 6:
+            mBlend.forEachSrcOut(image1, image2);
+            break;
+        case 7:
+            mBlend.forEachDstOut(image1, image2);
+            break;
+        case 8:
+            mBlend.forEachSrcAtop(image1, image2);
+            break;
+        case 9:
+            mBlend.forEachDstAtop(image1, image2);
+            break;
+        case 10:
+            mBlend.forEachXor(image1, image2);
+            break;
+        case 11:
+            mBlend.forEachAdd(image1, image2);
+            break;
+        case 12:
+            mBlend.forEachSubtract(image1, image2);
+            break;
+        case 13:
+            mBlend.forEachMultiply(image1, image2);
+            break;
+        }
+
+        mOutPixelsAllocation.copy2DRangeFrom(0, 0, image2.getType().getX(), image2.getType().getY(), image2, 0, 0);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index a8462e6..db0ef78 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -55,9 +55,11 @@
     private final String RESULT_FILE = "image_processing_result.csv";
 
     Bitmap mBitmapIn;
+    Bitmap mBitmapIn2;
     Bitmap mBitmapOut;
     String mTestNames[];
 
+    private Spinner mSpinner;
     private SeekBar mBar1;
     private SeekBar mBar2;
     private SeekBar mBar3;
@@ -81,6 +83,10 @@
 
     private TestBase mTest;
 
+    public void updateDisplay() {
+            mTest.updateBitmap(mBitmapOut);
+            mDisplayView.invalidate();
+    }
 
     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
         if (fromUser) {
@@ -98,8 +104,7 @@
             }
 
             mTest.runTest();
-            mTest.updateBitmap(mBitmapOut);
-            mDisplayView.invalidate();
+            updateDisplay();
         }
     }
 
@@ -110,6 +115,9 @@
     }
 
     void setupBars() {
+        mSpinner.setVisibility(View.VISIBLE);
+        mTest.onSpinner1Setup(mSpinner);
+
         mBar1.setVisibility(View.VISIBLE);
         mText1.setVisibility(View.VISIBLE);
         mTest.onBar1Setup(mBar1, mText1);
@@ -221,19 +229,21 @@
         case 27:
             mTest = new Mandelbrot();
             break;
+        case 28:
+            mTest = new Blend();
+            break;
         }
 
-        mTest.createBaseTest(this, mBitmapIn);
+        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2);
         setupBars();
 
         mTest.runTest();
-        mTest.updateBitmap(mBitmapOut);
-        mDisplayView.invalidate();
+        updateDisplay();
         mBenchmarkResult.setText("Result: not run");
     }
 
     void setupTests() {
-        mTestNames = new String[28];
+        mTestNames = new String[29];
         mTestNames[0] = "Levels Vec3 Relaxed";
         mTestNames[1] = "Levels Vec4 Relaxed";
         mTestNames[2] = "Levels Vec3 Full";
@@ -262,6 +272,7 @@
         mTestNames[25] = "Convolve 5x5";
         mTestNames[26] = "Intrinsics Convolve 5x5";
         mTestNames[27] = "Mandelbrot";
+        mTestNames[28] = "Intrinsics Blend";
 
         mTestSpinner.setAdapter(new ArrayAdapter<String>(
             this, R.layout.spinner_layout, mTestNames));
@@ -284,6 +295,7 @@
         setContentView(R.layout.main);
 
         mBitmapIn = loadBitmap(R.drawable.img1600x1067);
+        mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b);
         mBitmapOut = loadBitmap(R.drawable.img1600x1067);
 
         mSurfaceView = (SurfaceView) findViewById(R.id.surface);
@@ -291,6 +303,8 @@
         mDisplayView = (ImageView) findViewById(R.id.display);
         mDisplayView.setImageBitmap(mBitmapOut);
 
+        mSpinner = (Spinner) findViewById(R.id.spinner1);
+
         mBar1 = (SeekBar) findViewById(R.id.slider1);
         mBar2 = (SeekBar) findViewById(R.id.slider2);
         mBar3 = (SeekBar) findViewById(R.id.slider3);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
index 6885181..8009daa 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
@@ -36,14 +36,18 @@
 import android.view.View;
 import android.util.Log;
 import java.lang.Math;
+import android.widget.Spinner;
 
 public class TestBase  {
     protected final String TAG = "Img";
 
     protected RenderScript mRS;
     protected Allocation mInPixelsAllocation;
+    protected Allocation mInPixelsAllocation2;
     protected Allocation mOutPixelsAllocation;
 
+    protected ImageProcessingActivity act;
+
     // Override to use UI elements
     public void onBar1Changed(int progress) {
     }
@@ -84,11 +88,20 @@
         return false;
     }
 
-    public final void createBaseTest(ImageProcessingActivity act, Bitmap b) {
+    public boolean onSpinner1Setup(Spinner s) {
+        s.setVisibility(View.INVISIBLE);
+        return false;
+    }
+
+    public final void createBaseTest(ImageProcessingActivity ipact, Bitmap b, Bitmap b2) {
+        act = ipact;
         mRS = RenderScript.create(act);
         mInPixelsAllocation = Allocation.createFromBitmap(mRS, b,
                                                           Allocation.MipmapControl.MIPMAP_NONE,
                                                           Allocation.USAGE_SCRIPT);
+        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2,
+                                                          Allocation.MipmapControl.MIPMAP_NONE,
+                                                          Allocation.USAGE_SCRIPT);
         mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b,
                                                            Allocation.MipmapControl.MIPMAP_NONE,
                                                            Allocation.USAGE_SCRIPT);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs
new file mode 100644
index 0000000..87b56f77
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs
@@ -0,0 +1,24 @@
+// Copyright (C) 2011 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.
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+
+uchar alpha = 0x0;
+
+void setImageAlpha(uchar4 *v_out, uint32_t x, uint32_t y) {
+  v_out->rgba = convert_uchar4((convert_uint4(v_out->rgba) * alpha) >> (uint4)8);
+  v_out->a = alpha;
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 83fadcb..7662007 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -72,6 +72,7 @@
         unitTests.add(new UT_array_alloc(this, mRes, mCtx));
         unitTests.add(new UT_kernel(this, mRes, mCtx));
         unitTests.add(new UT_kernel_struct(this, mRes, mCtx));
+        unitTests.add(new UT_bug_char(this, mRes, mCtx));
         unitTests.add(new UT_clamp(this, mRes, mCtx));
         unitTests.add(new UT_clamp_relaxed(this, mRes, mCtx));
         unitTests.add(new UT_convert(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_bug_char.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_bug_char.java
new file mode 100644
index 0000000..faf3a31
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_bug_char.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+import java.util.Arrays;
+
+public class UT_bug_char extends UnitTest {
+    private Resources mRes;
+
+    protected UT_bug_char(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Bug Char", ctx);
+        mRes = res;
+    }
+
+    // packing functions
+    private Byte2 pack_b2(byte[] val) {
+        assert val.length == 2;
+        Log.i("bug_char", "pack_b2 " + val[0] + " " + val[1]);
+        return new Byte2(val[0], val[1]);
+    }
+
+    private byte min(byte v1, byte v2) {
+        return v1 < v2 ? v1 : v2;
+    }
+    private byte[] min(byte[] v1, byte[] v2) {
+        assert v1.length == v2.length;
+        byte[] rv = new byte[v1.length];
+        for (int i = 0; i < v1.length; ++i)
+            rv[i] = min(v1[i], v2[i]);
+        return rv;
+    }
+
+    private void initializeValues(ScriptC_bug_char s) {
+        byte rand_sc1_0 = (byte)7;
+        byte[] rand_sc2_0 = new byte[2];
+        rand_sc2_0[0] = 11;
+        rand_sc2_0[1] = 21;
+        Log.i("bug_char", "Generated sc2_0 to " + Arrays.toString(rand_sc2_0));
+        byte rand_sc1_1 = (byte)10;
+        byte[] rand_sc2_1 = new byte[2];
+        rand_sc2_1[0] = 13;
+        rand_sc2_1[1] = 15;
+        Log.i("bug_char", "Generated sc2_1 to " + Arrays.toString(rand_sc2_1));
+
+        s.set_rand_sc1_0(rand_sc1_0);
+        s.set_rand_sc2_0(pack_b2(rand_sc2_0));
+        s.set_rand_sc1_1(rand_sc1_1);
+        s.set_rand_sc2_1(pack_b2(rand_sc2_1));
+        // Set results for min
+        s.set_min_rand_sc1_sc1(min(rand_sc1_0, rand_sc1_1));
+        byte[] min_rand_sc2_raw = min(rand_sc2_0, rand_sc2_1);
+        Log.i("bug_char", "Generating min_rand_sc2_sc2 to " +
+              Arrays.toString(min_rand_sc2_raw));
+        Byte2 min_rand_sc2 = pack_b2(min_rand_sc2_raw);
+        Log.i("bug_char", "Setting min_rand_sc2_sc2 to [" + min_rand_sc2.x +
+              ", " + min_rand_sc2.y + "]");
+        s.set_min_rand_sc2_sc2(min_rand_sc2);
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_bug_char s = new ScriptC_bug_char(pRS, mRes,
+                R.raw.bug_char);
+        pRS.setMessageHandler(mRsMessage);
+        initializeValues(s);
+        s.invoke_bug_char_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java
index 40f7213..220509c 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java
@@ -347,8 +347,6 @@
         long[] rand_sl2_1 = randvec_long(2);
         long[] rand_sl3_1 = randvec_long(3);
         long[] rand_sl4_1 = randvec_long(4);
-        // FIXME:  generate signed char vectors once bug 6865598 is fixed
-        /*
         byte rand_sc1_0 = (byte)rand.nextInt(0x1 << 8);
         byte[] rand_sc2_0 = randvec_char(2);
         byte[] rand_sc3_0 = randvec_char(3);
@@ -357,7 +355,6 @@
         byte[] rand_sc2_1 = randvec_char(2);
         byte[] rand_sc3_1 = randvec_char(3);
         byte[] rand_sc4_1 = randvec_char(4);
-        */
         // TODO:  generate unsigned long vectors
 
         // Set random vectors in renderscript code
@@ -417,8 +414,6 @@
         s.set_rand_uc2_0(pack_s2(rand_uc2_0));
         s.set_rand_uc3_0(pack_s3(rand_uc3_0));
         s.set_rand_uc4_0(pack_s4(rand_uc4_0));
-        // FIXME:  set char input vectors once bug 6865598 is fixed
-        /*
         s.set_rand_sc1_0(rand_sc1_0);
         s.set_rand_sc2_0(pack_b2(rand_sc2_0));
         s.set_rand_sc3_0(pack_b3(rand_sc3_0));
@@ -427,7 +422,6 @@
         s.set_rand_sc2_1(pack_b2(rand_sc2_1));
         s.set_rand_sc3_1(pack_b3(rand_sc3_1));
         s.set_rand_sc4_1(pack_b4(rand_sc4_1));
-        */
         // TODO:  set unsigned long vectors
 
         // Set results for min
@@ -459,13 +453,10 @@
         s.set_min_rand_sl2_sl2(pack_l2(min(rand_sl2_0, rand_sl2_1)));
         s.set_min_rand_sl3_sl3(pack_l3(min(rand_sl3_0, rand_sl3_1)));
         s.set_min_rand_sl4_sl4(pack_l4(min(rand_sl4_0, rand_sl4_1)));
-        // FIXME:  set char min reference vectors once bug 6865598 is fixed
-        /*
         s.set_min_rand_sc1_sc1(min(rand_sc1_0, rand_sc1_1));
         s.set_min_rand_sc2_sc2(pack_b2(min(rand_sc2_0, rand_sc2_1)));
         s.set_min_rand_sc3_sc3(pack_b3(min(rand_sc3_0, rand_sc3_1)));
         s.set_min_rand_sc4_sc4(pack_b4(min(rand_sc4_0, rand_sc4_1)));
-        */
         // TODO:  set results for unsigned long min
 
         // Set results for max
@@ -497,13 +488,10 @@
         s.set_max_rand_sl2_sl2(pack_l2(max(rand_sl2_0, rand_sl2_1)));
         s.set_max_rand_sl3_sl3(pack_l3(max(rand_sl3_0, rand_sl3_1)));
         s.set_max_rand_sl4_sl4(pack_l4(max(rand_sl4_0, rand_sl4_1)));
-        // FIXME:  set signed char max reference vectors once bug 6865598 is fixed
-        /*
         s.set_max_rand_sc1_sc1(max(rand_sc1_0, rand_sc1_1));
         s.set_max_rand_sc2_sc2(pack_b2(max(rand_sc2_0, rand_sc2_1)));
         s.set_max_rand_sc3_sc3(pack_b3(max(rand_sc3_0, rand_sc3_1)));
         s.set_max_rand_sc4_sc4(pack_b4(max(rand_sc4_0, rand_sc4_1)));
-        */
 
         // TODO:  set results for unsigned long max
 
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/bug_char.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/bug_char.rs
new file mode 100644
index 0000000..dcd7b72
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/bug_char.rs
@@ -0,0 +1,47 @@
+#include "shared.rsh"
+
+char rand_sc1_0, rand_sc1_1;
+char2 rand_sc2_0, rand_sc2_1;
+
+char min_rand_sc1_sc1;
+char2 min_rand_sc2_sc2;
+
+static bool test_bug_char() {
+    bool failed = false;
+
+    rsDebug("rand_sc2_0.x: ", rand_sc2_0.x);
+    rsDebug("rand_sc2_0.y: ", rand_sc2_0.y);
+    rsDebug("rand_sc2_1.x: ", rand_sc2_1.x);
+    rsDebug("rand_sc2_1.y: ", rand_sc2_1.y);
+    char temp_sc1;
+    char2 temp_sc2;
+
+    temp_sc1 = min( rand_sc1_0, rand_sc1_1 );
+    if (temp_sc1 != min_rand_sc1_sc1) {
+        rsDebug("temp_sc1", temp_sc1);
+        failed = true;
+    }
+    rsDebug("broken", 'y');
+
+    temp_sc2 = min( rand_sc2_0, rand_sc2_1 );
+    if (temp_sc2.x != min_rand_sc2_sc2.x
+            || temp_sc2.y != min_rand_sc2_sc2.y) {
+        failed = true;
+    }
+
+
+    return failed;
+}
+
+void bug_char_test() {
+    bool failed = false;
+    failed |= test_bug_char();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs
index 1adb036..5bfbb2b 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs
@@ -338,16 +338,13 @@
 
 #define TEST_VEC_VEC_ALL(func)  \
 TEST_FN_FN_ALL(func)            \
+TEST_SC_SC_ALL(func)            \
 TEST_UC_UC_ALL(func)            \
 TEST_SS_SS_ALL(func)            \
 TEST_US_US_ALL(func)            \
 TEST_SI_SI_ALL(func)            \
 TEST_UI_UI_ALL(func)
 
-// FIXME:  Add char tests back in once bug 6865598 is fixed
-#if 0
-TEST_SC_SC_ALL(func)
-#endif
 // TODO:  add long types to ALL macro
 #if 0
 TEST_SL_SL_ALL(func)            \
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 0c85204..0cf0f21 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -60,6 +60,11 @@
     }
 
     @Override
+    public void nap(long arg0) throws RemoteException {
+        // pass for now.
+    }
+
+    @Override
     public void preventScreenOn(boolean arg0) throws RemoteException {
         // pass for now.
     }