Merge "Pass changed NetworkInfo to LocationProvider." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 4b43318..cc67e89 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19927,6 +19927,50 @@
 
 }
 
+package android.service.dreams {
+
+  public class Dream extends android.app.Service implements android.view.Window.Callback {
+    ctor public Dream();
+    method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
+    method public boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public boolean dispatchTouchEvent(android.view.MotionEvent);
+    method public boolean dispatchTrackballEvent(android.view.MotionEvent);
+    method public android.view.View findViewById(int);
+    method public void finish();
+    method public android.view.Window getWindow();
+    method public android.view.WindowManager getWindowManager();
+    method public boolean isInteractive();
+    method protected void lightsOut();
+    method public void onActionModeFinished(android.view.ActionMode);
+    method public void onActionModeStarted(android.view.ActionMode);
+    method public void onAttachedToWindow();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onContentChanged();
+    method public boolean onCreatePanelMenu(int, android.view.Menu);
+    method public android.view.View onCreatePanelView(int);
+    method public void onDetachedFromWindow();
+    method public boolean onMenuItemSelected(int, android.view.MenuItem);
+    method public boolean onMenuOpened(int, android.view.Menu);
+    method public void onPanelClosed(int, android.view.Menu);
+    method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+    method public boolean onSearchRequested();
+    method public void onStart();
+    method public final int onStartCommand(android.content.Intent, int, int);
+    method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public void onWindowFocusChanged(boolean);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public void setContentView(int);
+    method public void setContentView(android.view.View);
+    method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public void setInteractive(boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.Dream";
+  }
+
+}
+
 package android.service.textservice {
 
   public abstract class SpellCheckerService extends android.app.Service {
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index 83464c9..9a903e4 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -1,26 +1,31 @@
 /**
- * 
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 package android.service.dreams;
 
-import com.android.internal.policy.PolicyManager;
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
-import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.graphics.drawable.ColorDrawable;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Slog;
 import android.view.ActionMode;
-import android.view.IWindowManager;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -28,14 +33,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+
+import com.android.internal.policy.PolicyManager;
 
 /**
- * @hide
- *
+ *  Extend this class to implement a custom screensaver.
  */
 public class Dream extends Service implements Window.Callback {
     private final static boolean DEBUG = true;
@@ -61,7 +66,7 @@
     final Handler mHandler = new Handler();
     
     boolean mFinished = false;
-    
+
     // begin Window.Callback methods
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
@@ -210,19 +215,14 @@
 
         mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
     }
-    
+
     /**
-     * Called when this Dream is started. Place your initialization here.
-     * 
-     * Subclasses must call through to the superclass implementation.
-     * 
-     * XXX(dsandler) Might want to make this final and have a different method for clients to override 
+     * Called when this Dream is started.
      */
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        return super.onStartCommand(intent, flags, startId);
+    public void onStart() {
+        // hook for subclasses
     }
-    
+
    /**
      * Inflate a layout resource and set it to be the content view for this Dream.
      * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
@@ -351,9 +351,12 @@
             @Override
             public void run() {
                 if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId());
-                
+
                 getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
-            }});        
+
+                // start it up
+                onStart();
+            }});
     }
     
     /**
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index 4a14ced..d6b38a1 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -114,11 +114,19 @@
         if (DEBUG) Slog.v(TAG, "awaken()");
         synchronized (mLock) {
             if (mCurrentDream != null) {
+                if (DEBUG) Slog.v(TAG, "disconnecting: " +  mCurrentDreamComponent + " service: " + mCurrentDream);
                 mContext.unbindService(this);
+                mCurrentDream = null;
+                mCurrentDreamToken = null;
             }
         }
     }
 
+    // IDreamManager method
+    public boolean isDreaming() {
+        return mCurrentDream != null;
+    }
+
     public void bindDreamComponentL(ComponentName componentName, boolean test) {
         if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName
                 + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -129,11 +137,7 @@
                 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                 )
             .putExtra("android.dreams.TEST", test);
-        
-        if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
-            Slog.w(TAG, "unable to bind service: " + componentName);
-            return;
-        }
+
         mCurrentDreamComponent = componentName;
         mCurrentDreamToken = new Binder();
         try {
@@ -145,6 +149,9 @@
             Slog.w(TAG, "Unable to add window token. Proceed at your own risk.");
         }
         
+        if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+            Slog.w(TAG, "unable to bind service: " + componentName);
+        }
     }
 
     @Override
@@ -163,8 +170,7 @@
     @Override
     public void onServiceDisconnected(ComponentName name) {
         if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream);
-        mCurrentDream = null;
-        mCurrentDreamToken = null;
+        // Only happens in exceptional circumstances
     }
     
     @Override
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 7225013..b64dd8f 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -27,4 +27,5 @@
     void setDreamComponent(in ComponentName componentName);
     ComponentName getDreamComponent();
     void testDream(in ComponentName componentName);
+    boolean isDreaming();
 }
\ No newline at end of file
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index abab268..5f5d1f2 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -469,6 +469,8 @@
     public native   void setFlags(int flags, int mask);
     /** @hide */
     public native   void setWindowCrop(Rect crop);
+    /** @hide */
+    public native   void setDisplayId(int displayId);
 
 
    
diff --git a/core/java/android/widget/package.html b/core/java/android/widget/package.html
index 7d94a4b..91d327c 100644
--- a/core/java/android/widget/package.html
+++ b/core/java/android/widget/package.html
@@ -1,11 +1,16 @@
 <HTML>
 <BODY>
+<p>
 The widget package contains (mostly visual) UI elements to use
-on your Application screen. You can design your own <p>
+on your Application screen. You can also design your own.
+</p>
+
+<p>
 To create your own widget, extend {@link android.view.View} or a subclass. To
 use your widget in layout XML, there are two additional files for you to
 create. Here is a list of files you'll need to create to implement a custom
 widget:
+</p>
 <ul>
 <li><b>Java implementation file</b> - This is the file that implements the
 behavior of the widget. If you can instantiate the object from layout XML,
@@ -19,14 +24,16 @@
 res/layout/ that describes the layout of your widget. You could also do
 this in code in your Java file.</li>
 </ul>
+
+<p>
 ApiDemos sample application has an example of creating a custom layout XML
 tag, LabelView. See the following files that demonstrate implementing and using
-a custom widget:</p>
+a custom widget:
+</p>
 <ul>
-    <li><strong>LabelView.java</strong> - The implentation file</li>
+    <li><strong>LabelView.java</strong> - The implementation file</li>
     <li><strong>res/values/attrs.xml</strong> - Definition file</li>
-    <li><strong>res/layout/custom_view_1.xml</strong> - Layout
-file</li>
+    <li><strong>res/layout/custom_view_1.xml</strong> - Layout file</li>
 </ul>
 </BODY>
 </HTML>
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3cd28b1..3ad6406 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -717,6 +717,14 @@
     }
 }
 
+static void Surface_setDisplayId(JNIEnv* env, jobject thiz, jint displayId)
+{
+    const sp<SurfaceControl>& surface(getSurfaceControl(env, thiz));
+    if (surface == 0) return;
+
+    // TODO(mathias): Everything.
+}
+
 // ----------------------------------------------------------------------------
 
 static void Surface_copyFrom(
@@ -855,6 +863,7 @@
     {"writeToParcel",       "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
     {"isConsumerRunningBehind", "()Z", (void*)Surface_isConsumerRunningBehind },
     {"setWindowCrop",       "(Landroid/graphics/Rect;)V", (void*)Surface_setWindowCrop },
+    {"setDisplayId",        "(I)V", (void*)Surface_setDisplayId },
 };
 
 void nativeClassInit(JNIEnv* env, jclass clazz)
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 39129e5..b752471 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -852,7 +852,7 @@
     <string name="config_wimaxStateTrackerClassname" translatable="false"></string>
 
     <!-- enable screen saver feature -->
-    <bool name="config_enableDreams">false</bool>
+    <bool name="config_enableDreams">true</bool>
     <!-- Name of screensaver components to look for if none has been chosen by the user -->
     <string name="config_defaultDreamComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a54c188..1947c32 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -11,6 +11,7 @@
 		Caches.cpp \
 		DisplayListLogBuffer.cpp \
 		DisplayListRenderer.cpp \
+		Dither.cpp \
 		FboCache.cpp \
 		GradientCache.cpp \
 		LayerCache.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 258ced0..aa2bc3f 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -252,6 +252,7 @@
             dropShadowCache.clear();
             gradientCache.clear();
             fontRenderer->clear();
+            dither.clear();
             // fall through
         case kFlushMode_Moderate:
             fontRenderer->flush();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 4cbac41..ad1098c 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -38,6 +38,7 @@
 #include "TextDropShadowCache.h"
 #include "FboCache.h"
 #include "ResourceCache.h"
+#include "Dither.h"
 
 namespace android {
 namespace uirenderer {
@@ -250,6 +251,7 @@
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
     ResourceCache resourceCache;
+    Dither dither;
 
     GammaFontRenderer* fontRenderer;
 
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
new file mode 100755
index 0000000..5817977
--- /dev/null
+++ b/libs/hwui/Dither.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#include "Caches.h"
+#include "Dither.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Must be a power of two
+#define DITHER_KERNEL_SIZE 4
+
+///////////////////////////////////////////////////////////////////////////////
+// Lifecycle
+///////////////////////////////////////////////////////////////////////////////
+
+void Dither::bindDitherTexture() {
+    if (!mInitialized) {
+        const uint8_t pattern[] = {
+             0,  8,  2, 10,
+            12,  4, 14,  6,
+             3, 11,  1,  9,
+            15,  7, 13,  5
+        };
+
+        glGenTextures(1, &mDitherTexture);
+        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
+
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
+                GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
+
+        mInitialized = true;
+    } else {
+        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
+    }
+}
+
+void Dither::clear() {
+    if (mInitialized) {
+        glDeleteTextures(1, &mDitherTexture);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Program management
+///////////////////////////////////////////////////////////////////////////////
+
+void Dither::setupProgram(Program* program, GLuint* textureUnit) {
+    GLuint textureSlot = (*textureUnit)++;
+    Caches::getInstance().activeTexture(textureSlot);
+
+    bindDitherTexture();
+
+    glUniform1i(program->getUniform("ditherSampler"), textureSlot);
+    glUniform1f(program->getUniform("ditherSize"), 1.0f / DITHER_KERNEL_SIZE);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
new file mode 100755
index 0000000..34cf9bf
--- /dev/null
+++ b/libs/hwui/Dither.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_DITHER_H
+#define ANDROID_HWUI_DITHER_H
+
+#include <GLES2/gl2.h>
+
+#include "Program.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Handles dithering for programs.
+ */
+class Dither {
+public:
+    Dither(): mInitialized(false), mDitherTexture(0) { }
+
+    void clear();
+    void setupProgram(Program* program, GLuint* textureUnit);
+
+private:
+    void bindDitherTexture();
+
+    bool mInitialized;
+    GLuint mDitherTexture;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_DITHER_H
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index d601f01..0e77cb2 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -75,9 +75,11 @@
         // Linear
         "varying highp vec2 linear;\n",
         "varying highp float linear;\n",
+
         // Circular
         "varying highp vec2 circular;\n",
         "varying highp vec2 circular;\n",
+
         // Sweep
         "varying highp vec2 sweep;\n",
         "varying highp vec2 sweep;\n",
@@ -92,9 +94,11 @@
         // Linear
         "    linear = vec2((screenSpace * position).x, 0.5);\n",
         "    linear = (screenSpace * position).x;\n",
+
         // Circular
         "    circular = (screenSpace * position).xy;\n",
         "    circular = (screenSpace * position).xy;\n",
+
         // Sweep
         "    sweep = (screenSpace * position).xy;\n",
         "    sweep = (screenSpace * position).xy;\n",
@@ -137,19 +141,24 @@
         "uniform sampler2D sampler;\n";
 const char* gFS_Uniforms_ExternalTextureSampler =
         "uniform samplerExternalOES sampler;\n";
+#define FS_UNIFORMS_DITHER \
+        "uniform float ditherSize;\n" \
+        "uniform sampler2D ditherSampler;\n"
+#define FS_UNIFORMS_GRADIENT \
+        "uniform vec4 startColor;\n" \
+        "uniform vec4 endColor;\n"
 const char* gFS_Uniforms_GradientSampler[6] = {
         // Linear
-        "uniform sampler2D gradientSampler;\n",
-        "uniform vec4 startColor;\n"
-        "uniform vec4 endColor;\n",
+        FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
+        FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT,
+
         // Circular
-        "uniform sampler2D gradientSampler;\n",
-        "uniform vec4 startColor;\n"
-        "uniform vec4 endColor;\n",
+        FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
+        FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT,
+
         // Sweep
-        "uniform sampler2D gradientSampler;\n",
-        "uniform vec4 startColor;\n"
-        "uniform vec4 endColor;\n",
+        FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
+        FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT
 };
 const char* gFS_Uniforms_BitmapSampler =
         "uniform sampler2D bitmapSampler;\n";
@@ -176,6 +185,11 @@
         "    highp vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
         "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
 
+#define FS_MAIN_DITHER \
+        "texture2D(ditherSampler, gl_FragCoord.xy * ditherSize).a * ditherSize * ditherSize"
+const char* gFS_Main_AddDitherToGradient =
+        "    gradientColor += " FS_MAIN_DITHER ";\n";
+
 // Fast cases
 const char* gFS_Fast_SingleColor =
         "\nvoid main(void) {\n"
@@ -207,18 +221,18 @@
         "}\n\n";
 const char* gFS_Fast_SingleGradient[2] = {
         "\nvoid main(void) {\n"
-        "    gl_FragColor = texture2D(gradientSampler, linear);\n"
+        "    gl_FragColor = " FS_MAIN_DITHER " + texture2D(gradientSampler, linear);\n"
         "}\n\n",
         "\nvoid main(void) {\n"
-        "    gl_FragColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+        "    gl_FragColor = " FS_MAIN_DITHER " + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
         "}\n\n"
 };
 const char* gFS_Fast_SingleModulateGradient[2] = {
         "\nvoid main(void) {\n"
-        "    gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
+        "    gl_FragColor " FS_MAIN_DITHER " + color.a * texture2D(gradientSampler, linear);\n"
         "}\n\n",
         "\nvoid main(void) {\n"
-        "    gl_FragColor = color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+        "    gl_FragColor " FS_MAIN_DITHER " + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
         "}\n\n"
 };
 
@@ -254,16 +268,21 @@
 };
 const char* gFS_Main_FetchGradient[6] = {
         // Linear
-        "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
-        "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+        "    highp vec4 gradientColor = texture2D(gradientSampler, linear);\n",
+
+        "    highp vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+
         // Circular
-        "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
-        "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+        "    highp vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
+
+        "    highp vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+
         // Sweep
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
+        "    highp vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
+
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+        "    highp vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
 };
 const char* gFS_Main_FetchBitmap =
         "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
@@ -651,6 +670,7 @@
         }
         if (description.hasGradient) {
             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
+            shader.append(gFS_Main_AddDitherToGradient);
         }
         if (description.hasBitmap) {
             if (description.isPoint) {
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 71e1739..8916efd0 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -250,6 +250,8 @@
         bindUniformColor(program->getUniform("endColor"), mColors[1]);
     }
 
+    Caches::getInstance().dither.setupProgram(program, textureUnit);
+
     mat4 screenSpace;
     computeScreenSpaceMatrix(screenSpace, modelView);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
@@ -375,6 +377,8 @@
        bindUniformColor(program->getUniform("endColor"), mColors[1]);
     }
 
+    Caches::getInstance().dither.setupProgram(program, textureUnit);
+
     mat4 screenSpace;
     computeScreenSpaceMatrix(screenSpace, modelView);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8ebbc52..4a73200 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -18,4 +18,5 @@
 <resources>
     <item type="id" name="expandable_tag" />
     <item type="id" name="user_expanded_tag" />
+    <item type="id" name="user_lock_tag" />
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 6aa7dcd..674d9a3 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -39,7 +39,8 @@
         View getChildAtRawPosition(float x, float y);
         View getChildAtPosition(float x, float y);
         boolean canChildBeExpanded(View v);
-        boolean setUserExpandedChild(View v, boolean userxpanded);
+        boolean setUserExpandedChild(View v, boolean userExpanded);
+        boolean setUserLockedChild(View v, boolean userLocked);
     }
 
     private static final String TAG = "ExpandHelper";
@@ -433,7 +434,7 @@
                     final int y = (int) ev.getY();
                     View underPointer = findView(x, y);
                     if (isFinished && underPointer != null && underPointer != mCurrView) {
-                        setGlow(0f);
+                        finishScale(false);
                         initScale(underPointer);
                         mInitialTouchY = ev.getY();
                         mHasPopped = false;
@@ -458,6 +459,7 @@
     private boolean initScale(View v) {
         if (v != null) {
             if (DEBUG) Slog.d(TAG, "scale begins on view: " + v);
+            mCallback.setUserLockedChild(v, true);
             setView(v);
             setGlow(GLOW_BASE);
             mScaler.setView(v);
@@ -479,21 +481,26 @@
     }
 
     private void finishScale(boolean force) {
+        float currentHeight = mScaler.getHeight();
+        float targetHeight = mSmallSize;
         float h = mScaler.getHeight();
         final boolean wasClosed = (mOldHeight == mSmallSize);
         if (wasClosed) {
-            h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize;
+            targetHeight = (force || currentHeight > mSmallSize) ? mNaturalHeight : mSmallSize;
         } else {
-            h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
+            targetHeight = (force || currentHeight < mNaturalHeight) ? mSmallSize : mNaturalHeight;
         }
         if (mScaleAnimation.isRunning()) {
             mScaleAnimation.cancel();
         }
-        mScaleAnimation.setFloatValues(h);
-        mScaleAnimation.setupStartValues();
-        mScaleAnimation.start();
         setGlow(0f);
         mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
+        if (targetHeight != currentHeight) {
+            mScaleAnimation.setFloatValues(targetHeight);
+            mScaleAnimation.setupStartValues();
+            mScaleAnimation.start();
+        }
+        mCallback.setUserLockedChild(mCurrView, false);
         if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index b392648..ea5089d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -780,16 +780,20 @@
         int N = mNotificationData.size();
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = mNotificationData.get(i);
-            if (i == (N-1)) {
-                if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
-                expandView(entry, true);
-            } else {
-                if (!entry.userExpanded()) {
-                    if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
-                    expandView(entry, false);
+            if (!entry.userLocked()) {
+                if (i == (N-1)) {
+                    if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
+                    expandView(entry, true);
                 } else {
-                    if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i);
+                    if (!entry.userExpanded()) {
+                        if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
+                        expandView(entry, false);
+                    } else {
+                        if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i);
+                    }
                 }
+            } else {
+                if (DEBUG) Slog.d(TAG, "ignoring notification being held by user at " + i);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index dfd8cf8..c82f250 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -71,6 +71,18 @@
         public boolean setUserExpanded(boolean userExpanded) {
             return NotificationData.setUserExpanded(row, userExpanded);
         }
+        /**
+         * Return whether the entry is being touched by the user.
+         */
+        public boolean userLocked() {
+            return NotificationData.getUserLocked(row);
+        }
+        /**
+         * Set the flag indicating that this is being touched by the user.
+         */
+        public boolean setUserLocked(boolean userLocked) {
+            return NotificationData.setUserLocked(row, userLocked);
+        }
     }
     private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
     private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
@@ -197,4 +209,18 @@
     public static boolean setUserExpanded(View row, boolean userExpanded) {
         return writeBooleanTag(row, R.id.user_expanded_tag, userExpanded);
     }
+
+    /**
+     * Return whether the entry is being touched by the user.
+     */
+    public static boolean getUserLocked(View row) {
+        return readBooleanTag(row, R.id.user_lock_tag);
+    }
+
+    /**
+     * Set whether the entry is being touched by the user.
+     */
+    public static boolean setUserLocked(View row, boolean userLocked) {
+        return writeBooleanTag(row, R.id.user_lock_tag, userLocked);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 61e5ab6..9fee49b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -161,6 +161,10 @@
         return NotificationData.setUserExpanded(v, userExpanded);
     }
 
+    public boolean setUserLockedChild(View v, boolean userLocked) {
+        return NotificationData.setUserLocked(v, userLocked);
+    }
+
     public void onChildDismissed(View v) {
         final View veto = v.findViewById(R.id.veto);
         if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 97b4cb5..215f597 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1132,7 +1132,7 @@
                     com.android.internal.R.bool.config_enableDreams);
             
             mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver,
-                    Settings.Secure.SCREENSAVER_ENABLED, 1);
+                    Settings.Secure.SCREENSAVER_ENABLED, 0);
 
             if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
                 mScreenSaverTimeout = Settings.Secure.getInt(resolver,
@@ -4076,7 +4076,9 @@
             if (dm == null) return;
             
             try {
-                if (localLOGV) Log.v(TAG, "startScreenSaver: awakening...");
+                if (!dm.isDreaming()) return;
+
+                if (localLOGV) Log.v(TAG, "stopScreenSaver: awakening...");
                 
                 dm.awaken();
             } catch (RemoteException ex) {
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index e7dac72..8bac52c 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -29,9 +29,12 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.provider.Settings;
+import android.service.dreams.IDreamManager;
 import android.util.Log;
 import android.util.Slog;
 
@@ -194,7 +197,29 @@
                             }
                         }
 
-                        mContext.sendStickyBroadcast(intent);
+                        IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
+                        if (mgr != null) {
+                            // dreams feature enabled
+                            boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED;
+                            if (undocked) {
+                                try {
+                                    if (mgr.isDreaming()) {
+                                        mgr.awaken();
+                                    }
+                                } catch (RemoteException e) {
+                                    Slog.w(TAG, "Unable to awaken!", e);
+                                }
+                            } else {
+                                try {
+                                    mgr.dream();
+                                } catch (RemoteException e) {
+                                    Slog.w(TAG, "Unable to dream!", e);
+                                }
+                            }
+                        } else {
+                            // dreams feature not enabled, send legacy intent
+                            mContext.sendStickyBroadcast(intent);
+                        }
                     }
                     break;
             }
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index b9c9ffd..468bf21 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -62,6 +62,9 @@
     /** All the DisplayInfos in the system indexed by deviceId */
     private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<DisplayInfo>();
 
+    private final ArrayList<DisplayCallback> mCallbacks =
+            new ArrayList<DisplayManagerService.DisplayCallback>();
+
     public DisplayManagerService() {
         mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
         registerDefaultDisplayAdapter();
@@ -131,8 +134,20 @@
      * @param adapter The wrapper for information associated with the physical display.
      */
     public void registerDisplayAdapter(DisplayAdapter adapter) {
+
+        int displayId;
+        DisplayCallback[] callbacks;
+
         synchronized (mLock) {
-            int displayId = mDisplayIdSeq++;
+            displayId = mDisplayIdSeq;
+            do {
+                // Find the next unused displayId. (Pretend like it might ever wrap around).
+                mDisplayIdSeq++;
+                if (mDisplayIdSeq < 0) {
+                    mDisplayIdSeq = Display.DEFAULT_DISPLAY + 1;
+                }
+            } while (mDisplayInfos.get(mDisplayIdSeq) != null);
+
             adapter.setDisplayId(displayId);
 
             createDisplayInfoLocked(displayId, adapter);
@@ -142,6 +157,11 @@
             mLogicalToPhysicals.put(displayId, list);
 
             mDisplayAdapters.add(adapter);
+            callbacks = mCallbacks.toArray(new DisplayCallback[mCallbacks.size()]);
+        }
+
+        for (int i = callbacks.length - 1; i >= 0; i--) {
+            callbacks[i].displayAdded(displayId);
         }
 
         // TODO: Notify SurfaceFlinger of new addition.
@@ -188,7 +208,6 @@
                 list = new ArrayList<DisplayAdapter>();
                 mLogicalToPhysicals.put(displayId, list);
             }
-
             list.add(adapter);
             adapter.setDisplayId(displayId);
         }
@@ -219,6 +238,20 @@
         // TODO: Notify SurfaceFlinger of removal.
     }
 
+    public void registerDisplayCallback(final DisplayCallback callback) {
+        synchronized (mLock) {
+            if (!mCallbacks.contains(callback)) {
+                mCallbacks.add(callback);
+            }
+        }
+    }
+
+    public void unregisterDisplayCallback(final DisplayCallback callback) {
+        synchronized (mLock) {
+            mCallbacks.remove(callback);
+        }
+    }
+
     /**
      * Create a new logical DisplayInfo and fill it in with information from the physical display.
      * @param displayId The logical identifier.
@@ -288,11 +321,17 @@
 
         DisplayDeviceInfo info = new DisplayDeviceInfo();
         for (DisplayAdapter adapter : mDisplayAdapters) {
-            pw.println("Display for adapter " + adapter.getName());
+            pw.println("Display for adapter " + adapter.getName()
+                + " assigned to Display " + adapter.getDisplayId());
             DisplayDevice device = adapter.getDisplayDevice();
             pw.print("  ");
             device.getInfo(info);
             pw.println(info);
         }
     }
+
+    public interface DisplayCallback {
+        public void displayAdded(int displayId);
+        public void displayRemoved(int displayId);
+    }
 }
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 453c7a4..cb6db3c 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -424,6 +424,11 @@
                             forceUserActivityLocked();
                         }
                     }
+
+                    // stop the screensaver if we're now unplugged
+                    if (mPolicy != null) {
+                        mPolicy.stopScreenSaver();
+                    }
                 }
             }
         }
@@ -1826,7 +1831,7 @@
             final boolean stateChanged = mPowerState != newState;
 
             if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) {
-                if (mPolicy != null && mPolicy.isScreenSaverEnabled()) {
+                if (mPolicy != null && mPolicy.isScreenSaverEnabled() && mIsPowered) {
                     if (DEBUG) {
                         Slog.d(TAG, "setPowerState: running screen saver instead of turning off screen");
                     }
@@ -1922,6 +1927,13 @@
                     } else {
                         err = 0;
                     }
+
+                    // stop the screensaver if user turned screen off
+                    if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
+                        if (mPolicy != null) {
+                            mPolicy.stopScreenSaver();
+                        }
+                    }
                 }
             } else if (stateChanged) {
                 // Screen on/off didn't change, but lights may have.
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index f1c69f2..d931426 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -474,6 +474,7 @@
         private final Point mSize = new Point();
         private final Rect mWindowCrop = new Rect();
         private boolean mShown = false;
+        private int mDisplayId;
         private String mName = "Not named";
 
         public SurfaceTrace(SurfaceSession s,
@@ -481,6 +482,7 @@
                        OutOfResourcesException {
             super(s, pid, displayId, w, h, format, flags);
             mSize.set(w, h);
+            mDisplayId = displayId;
             Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
                     + Debug.getCallers(3));
         }
@@ -548,6 +550,13 @@
         }
 
         @Override
+        public void setDisplayId(int displayId) {
+            super.setDisplayId(displayId);
+            mDisplayId = displayId;
+            Slog.v(SURFACE_TAG, "setDisplayId: " + this + ". Called by " + Debug.getCallers(3));
+        }
+
+        @Override
         public void hide() {
             super.hide();
             mShown = false;
@@ -588,7 +597,7 @@
         @Override
         public String toString() {
             return "Surface " + Integer.toHexString(System.identityHashCode(this)) + " "
-                    + mName + ": shown=" + mShown + " layer=" + mLayer
+                    + mName + " (" + mDisplayId + "): shown=" + mShown + " layer=" + mLayer
                     + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
                     + " " + mSize.x + "x" + mSize.y
                     + " crop=" + mWindowCrop.toShortString();
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
index ed00ecd..a73eab5 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientStopsActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.LinearGradient;
 import android.graphics.Paint;
 import android.graphics.Shader;
@@ -111,6 +112,14 @@
 
             canvas.translate(0.0f, 75.0f);
             canvas.drawRect(0.0f, 0.0f, 768.0f, 50.0f, paint);
+
+            gradient = new LinearGradient(0.0f, 0.0f, 512.0f, 0.0f,
+                    colors, null, Shader.TileMode.CLAMP);
+
+            paint.setShader(gradient);
+
+            canvas.translate(0.0f, 75.0f);
+            canvas.drawRect(0.0f, 0.0f, 512.0f, 50.0f, paint);
         }
     }
 }