Merge change Id4d04def into eclair

* changes:
  Fix a race that kept the locale picker from working under heavy CPU load.
diff --git a/Android.mk b/Android.mk
index 5d4c5c1..d92809a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -489,6 +489,8 @@
 
 include $(BUILD_DROIDDOC)
 
+# explicitly specify that online-sdk depends on framework-res.
+$(full_target): framework-res-package-target
 
 # ==== docs that have all of the stuff that's @hidden =======================
 include $(CLEAR_VARS)
diff --git a/api/current.xml b/api/current.xml
index 8f83e39..47dc08a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -99410,6 +99410,17 @@
  visibility="public"
 >
 </field>
+<field name="ECLAIR_MR1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Bundle"
  extends="java.lang.Object"
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0f8bc08..d4aaba3 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -103,16 +103,19 @@
          * October 2008: The original, first, version of Android.  Yay!
          */
         public static final int BASE = 1;
+        
         /**
          * February 2009: First Android update, officially called 1.1.
          */
         public static final int BASE_1_1 = 2;
+        
         /**
          * May 2009: Android 1.5.
          */
         public static final int CUPCAKE = 3;
+        
         /**
-         * Current work on "Donut" development branch.
+         * September 2009: Android 1.6.
          * 
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -133,8 +136,9 @@
          * </ul>
          */
         public static final int DONUT = 4;
+        
         /**
-         * Current work on "Eclair" development branch.
+         * November 2009: Android 2.0
          * 
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -152,6 +156,11 @@
          * </ul>
          */
         public static final int ECLAIR = 5;
+        
+        /**
+         * Current work on Eclair MR1.
+         */
+        public static final int ECLAIR_MR1 = 6;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 86685fb..a5a4852 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1643,8 +1643,6 @@
 
     final DrawFilter mZoomFilter =
                     new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
-    final DrawFilter mScrollFilter =
-                    new PaintFlagsDrawFilter(SCROLL_BITS, 0);
 
     /* package */ void drawContentPicture(Canvas canvas, int color,
                                           boolean animatingZoom,
@@ -1653,7 +1651,7 @@
         if (animatingZoom) {
             df = mZoomFilter;
         } else if (animatingScroll) {
-            df = mScrollFilter;
+            df = null;
         }
         canvas.setDrawFilter(df);
         boolean tookTooLong = nativeDrawContent(canvas, color);
diff --git a/core/res/Android.mk b/core/res/Android.mk
index cb5524a..78cb86d 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -34,3 +34,7 @@
 LOCAL_EXPORT_PACKAGE_RESOURCES := true
 
 include $(BUILD_PACKAGE)
+
+# define a global intermediate target that other module may depend on.
+.PHONY: framework-res-package-target
+framework-res-package-target: $(LOCAL_BUILT_MODULE)
diff --git a/data/sounds/ringtones/FreeFlight.ogg b/data/sounds/ringtones/FreeFlight.ogg
new file mode 100644
index 0000000..76dfabe
--- /dev/null
+++ b/data/sounds/ringtones/FreeFlight.ogg
Binary files differ
diff --git a/data/sounds/ringtones/FreeFlight.wav b/data/sounds/ringtones/FreeFlight.wav
new file mode 100644
index 0000000..a4e14aa
--- /dev/null
+++ b/data/sounds/ringtones/FreeFlight.wav
Binary files differ
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 76f1213..47505e6 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -58,7 +58,7 @@
   <h2>Thank you for downloading the Android SDK!</h2>
   <p>Your download should be underway. If not, <a id="click-download">click here to start the download</a>.</p>
   <p>To set up your Android development environment, please read the guide to
-    <a href="installing.html" class="addVersionPath">Installing the Android SDK</a>.
+    <a href="installing.html">Installing the Android SDK</a>.
     Once you have completed the installation, see the
     <a href="/guide/index.html">Dev Guide</a> for documentation about
     developing Android applications.</p>
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 8897f03..2172536 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -66,7 +66,11 @@
     GraphicBuffer();
 
     // creates w * h buffer
-    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t ssage);
+    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+
+    // create a buffer from an existing handle
+    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+            uint32_t stride, native_handle_t* handle, bool keepOwnership);
 
     // return status
     status_t initCheck() const;
@@ -94,9 +98,15 @@
     GraphicBuffer(const Parcel& reply);
     virtual ~GraphicBuffer();
 
+    enum {
+        ownNone   = 0,
+        ownHandle = 1,
+        ownData   = 2,
+    };
+
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
     inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-    bool mOwner;
+    uint8_t mOwner;
 
 private:
     friend class Surface;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index cc39dac..eb388af 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -30,8 +30,21 @@
 
 pthread_key_t Context::gThreadTLSKey = 0;
 uint32_t Context::gThreadTLSKeyCount = 0;
+uint32_t Context::gGLContextCount = 0;
 pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
 
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+    if (returnVal != EGL_TRUE) {
+        fprintf(stderr, "%s() returned %d\n", op, returnVal);
+    }
+
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
+        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+                error);
+    }
+}
+
 void Context::initEGL()
 {
     mEGL.mNumConfigs = -1;
@@ -61,7 +74,10 @@
 
     LOGV("initEGL start");
     mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+
     eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion);
+    checkEglError("eglInitialize");
 
     status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig);
     if (err) {
@@ -76,9 +92,24 @@
              android_createDisplaySurface(),
              NULL);
     }
+    checkEglError("eglCreateWindowSurface");
+    if (mEGL.mSurface == EGL_NO_SURFACE) {
+        LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
+    }
 
-    mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL);
-    eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
+    mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, NULL);
+    checkEglError("eglCreateContext");
+    if (mEGL.mContext == EGL_NO_CONTEXT) {
+        LOGE("eglCreateContext returned EGL_NO_CONTEXT");
+    }
+    gGLContextCount++;
+
+    EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
+    checkEglError("eglCreateContext", ret);
+    if (mEGL.mContext == EGL_NO_CONTEXT) {
+        LOGE("eglCreateContext returned EGL_NO_CONTEXT");
+    }
+
     eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
     eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
 
@@ -101,6 +132,24 @@
     }
 }
 
+void Context::deinitEGL()
+{
+    EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    checkEglError("eglCreateContext", ret);
+    if (mEGL.mContext == EGL_NO_CONTEXT) {
+        LOGE("eglCreateContext returned EGL_NO_CONTEXT");
+    }
+
+    eglDestroyContext(mEGL.mDisplay, mEGL.mContext);
+    checkEglError("eglDestroyContext");
+
+    gGLContextCount--;
+    if (!gGLContextCount) {
+        eglTerminate(mEGL.mDisplay);
+    }
+}
+
+
 bool Context::runScript(Script *s, uint32_t launchID)
 {
     ObjectBaseRef<ProgramFragment> frag(mFragment);
@@ -232,7 +281,9 @@
      rsc->props.mLogScripts = getProp("debug.rs.script");
      rsc->props.mLogObjects = getProp("debug.rs.objects");
 
+     pthread_mutex_lock(&gInitMutex);
      rsc->initEGL();
+     pthread_mutex_unlock(&gInitMutex);
 
      ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
      if (!tlsStruct) {
@@ -294,7 +345,11 @@
      glClearColor(0,0,0,0);
      glClear(GL_COLOR_BUFFER_BIT);
      eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
-     eglTerminate(rsc->mEGL.mDisplay);
+
+     pthread_mutex_lock(&gInitMutex);
+     rsc->deinitEGL();
+     pthread_mutex_unlock(&gInitMutex);
+
      rsc->objDestroyOOBRun();
      LOGV("RS Thread exited");
      return NULL;
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 0dd90ed..c80fd5a 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -54,6 +54,7 @@
 
     static pthread_key_t gThreadTLSKey;
     static uint32_t gThreadTLSKeyCount;
+    static uint32_t gGLContextCount;
     static pthread_mutex_t gInitMutex;
 
     struct ScriptTLSStruct {
@@ -215,6 +216,7 @@
     Context();
 
     void initEGL();
+    void deinitEGL();
 
     bool runRootScript();
 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index f84933e..1abfd68 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -256,12 +256,16 @@
     if (strstr(gl_extensions, "GL_OES_draw_texture")) {
         mFlags |= DRAW_TEXTURE_EXTENSION;
     }
+#ifdef EGL_ANDROID_image_native_buffer
     if (strstr( gl_extensions, "GL_OES_EGL_image") &&
         (strstr(egl_extensions, "EGL_KHR_image_base") || 
                 strstr(egl_extensions, "EGL_KHR_image")) &&
         strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
         mFlags |= DIRECT_TEXTURE;
     }
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
 
     // Unbind the context from this thread
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 2bb1e12..f5a5a0b 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -130,62 +130,6 @@
     return NO_ERROR;
 }
 
-status_t Layer::initializeEglImageLocked(
-        const sp<GraphicBuffer>& buffer, Texture* texture)
-{
-    status_t err = NO_ERROR;
-
-    // we need to recreate the texture
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-
-    // free the previous image
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, texture->image);
-        texture->image = EGL_NO_IMAGE_KHR;
-    }
-
-    // construct an EGL_NATIVE_BUFFER_ANDROID
-    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
-
-    // create the new EGLImageKHR
-    const EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
-            EGL_NONE,                   EGL_NONE
-    };
-    texture->image = eglCreateImageKHR(
-            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-            (EGLClientBuffer)clientBuf, attrs);
-
-    LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
-            "eglCreateImageKHR() failed. err=0x%4x",
-            eglGetError());
-
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        glBindTexture(GL_TEXTURE_2D, texture->name);
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                (GLeglImageOES)texture->image);
-        GLint error = glGetError();
-        if (UNLIKELY(error != GL_NO_ERROR)) {
-            // this failed, for instance, because we don't support NPOT.
-            // FIXME: do something!
-            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
-                 "failed err=0x%04x",
-                 this, texture->image, error);
-            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-            err = INVALID_OPERATION;
-        } else {
-            // Everything went okay!
-            texture->NPOTAdjust = false;
-            texture->dirty  = false;
-            texture->width  = clientBuf->width;
-            texture->height = clientBuf->height;
-        }
-    } else {
-        err = INVALID_OPERATION;
-    }
-    return err;
-}
-
 void Layer::reloadTexture(const Region& dirty)
 {
     Mutex::Autolock _l(mLock);
@@ -199,10 +143,11 @@
         mTextures[index].height = 0;
     }
 
+#ifdef EGL_ANDROID_image_native_buffer
     if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
         if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {
             if (mTextures[index].dirty) {
-                initializeEglImageLocked(buffer, &mTextures[index]);
+                initializeEglImage(buffer, &mTextures[index]);
             }
         } else {
             if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width ||
@@ -212,7 +157,7 @@
                         buffer->width, buffer->height, buffer->format,
                         GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                         GraphicBuffer::USAGE_HW_TEXTURE);
-                initializeEglImageLocked(
+                initializeEglImage(
                         mHybridBuffer, &mTextures[0]);
             }
 
@@ -279,7 +224,9 @@
                 buffer->unlock();
             }
         }
-    } else {
+    } else
+#endif
+    {
         for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
             mTextures[i].image = EGL_NO_IMAGE_KHR;
         }
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 57b3dfa..1310ecc 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -85,8 +85,6 @@
     }
  
     void reloadTexture(const Region& dirty);
-    status_t initializeEglImageLocked(
-            const sp<GraphicBuffer>& buffer, Texture* texture);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index ecc7894..8003d22 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -617,6 +617,63 @@
     }
 }
 
+status_t LayerBase::initializeEglImage(
+        const sp<GraphicBuffer>& buffer, Texture* texture)
+{
+    status_t err = NO_ERROR;
+
+    // we need to recreate the texture
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+    // free the previous image
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, texture->image);
+        texture->image = EGL_NO_IMAGE_KHR;
+    }
+
+    // construct an EGL_NATIVE_BUFFER_ANDROID
+    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+    // create the new EGLImageKHR
+    const EGLint attrs[] = {
+            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
+            EGL_NONE,                   EGL_NONE
+    };
+    texture->image = eglCreateImageKHR(
+            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            (EGLClientBuffer)clientBuf, attrs);
+
+    LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
+            "eglCreateImageKHR() failed. err=0x%4x",
+            eglGetError());
+
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        glBindTexture(GL_TEXTURE_2D, texture->name);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                (GLeglImageOES)texture->image);
+        GLint error = glGetError();
+        if (UNLIKELY(error != GL_NO_ERROR)) {
+            // this failed, for instance, because we don't support NPOT.
+            // FIXME: do something!
+            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
+                 "failed err=0x%04x",
+                 this, texture->image, error);
+            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+            err = INVALID_OPERATION;
+        } else {
+            // Everything went okay!
+            texture->NPOTAdjust = false;
+            texture->dirty  = false;
+            texture->width  = clientBuf->width;
+            texture->height = clientBuf->height;
+        }
+    } else {
+        err = INVALID_OPERATION;
+    }
+    return err;
+}
+
+
 // ---------------------------------------------------------------------------
 
 int32_t LayerBaseClient::sIdentity = 0;
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index efa4f8c..ed07b3f 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -261,6 +261,8 @@
           void drawWithOpenGL(const Region& clip, const Texture& texture) const;
           void loadTexture(Texture* texture, 
                   const Region& dirty, const GGLSurface& t) const;
+          status_t initializeEglImage(
+                  const sp<GraphicBuffer>& buffer, Texture* texture);
 
           
                 sp<SurfaceFlinger> mFlinger;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 7e27a02..6590503 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -339,12 +339,6 @@
     mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
     mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
     mLayer.forceVisibilityTransaction();
-
-    hw_module_t const* module;
-    mBlitEngine = NULL;
-    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
-        copybit_open(module, &mBlitEngine);
-    }
 }
 
 LayerBuffer::BufferSource::~BufferSource()
@@ -352,8 +346,9 @@
     if (mTexture.name != -1U) {
         glDeleteTextures(1, &mTexture.name);
     }
-    if (mBlitEngine) {
-        copybit_close(mBlitEngine);
+    if (mTexture.image != EGL_NO_IMAGE_KHR) {
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        eglDestroyImageKHR(dpy, mTexture.image);
     }
 }
 
@@ -421,122 +416,28 @@
     status_t err = NO_ERROR;
     NativeBuffer src(ourBuffer->getBuffer());
     const Rect transformedBounds(mLayer.getTransformedBounds());
-    copybit_device_t* copybit = mBlitEngine;
 
-    if (copybit)  {
-        const int src_width  = src.crop.r - src.crop.l;
-        const int src_height = src.crop.b - src.crop.t;
-        int W = transformedBounds.width();
-        int H = transformedBounds.height();
-        if (mLayer.getOrientation() & Transform::ROT_90) {
-            int t(W); W=H; H=t;
-        }
+    if (UNLIKELY(mTexture.name == -1LU)) {
+        mTexture.name = mLayer.createTexture();
+    }
 
-#ifdef EGL_ANDROID_get_render_buffer
-        EGLDisplay dpy = eglGetCurrentDisplay();
-        EGLSurface draw = eglGetCurrentSurface(EGL_DRAW); 
-        EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw);
-        android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf;
-        if (nb == 0) {
-            err = BAD_VALUE;
-        } else {
-            copybit_image_t dst;
-            dst.w       = nb->width;
-            dst.h       = nb->height;
-            dst.format  = nb->format;
-            dst.base    = NULL; // unused by copybit on msm7k
-            dst.handle  = (native_handle_t *)nb->handle;
+#if defined(EGL_ANDROID_image_native_buffer)
+    if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
+         // NOTE: Assume the buffer is  allocated with the proper USAGE flags
+        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                src.crop.r, src.crop.b, src.img.format, 
+                GraphicBuffer::USAGE_HW_TEXTURE,
+                src.img.w, src.img.handle, false);
 
-            /* With LayerBuffer, it is likely that we'll have to rescale the
-             * surface, because this is often used for video playback or
-             * camera-preview. Since we want these operation as fast as possible
-             * we make sure we can use the 2D H/W even if it doesn't support
-             * the requested scale factor, in which case we perform the scaling
-             * in several passes. */
-
-            const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
-            const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
-
-            float xscale = 1.0f;
-            if (src_width > W*min)          xscale = 1.0f / min;
-            else if (src_width*mag < W)     xscale = mag;
-
-            float yscale = 1.0f;
-            if (src_height > H*min)         yscale = 1.0f / min;
-            else if (src_height*mag < H)    yscale = mag;
-
-            if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
-                const int tmp_w = floorf(src_width  * xscale);
-                const int tmp_h = floorf(src_height * yscale);
-                
-                if (mTempBitmap==0 || 
-                        mTempBitmap->getWidth() < size_t(tmp_w) || 
-                        mTempBitmap->getHeight() < size_t(tmp_h)) {
-                    mTempBitmap.clear();
-                    mTempBitmap = new GraphicBuffer(
-                            tmp_w, tmp_h, src.img.format, 
-                            GraphicBuffer::USAGE_HW_2D);
-                    err = mTempBitmap->initCheck();
-                }
-
-                if (LIKELY(err == NO_ERROR)) {
-                    NativeBuffer tmp;
-                    tmp.img.w = tmp_w;
-                    tmp.img.h = tmp_h;
-                    tmp.img.format = src.img.format;
-                    tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle;
-                    tmp.crop.l = 0;
-                    tmp.crop.t = 0;
-                    tmp.crop.r = tmp.img.w;
-                    tmp.crop.b = tmp.img.h;
-
-                    region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
-                    copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
-                    copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-                    copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
-                    err = copybit->stretch(copybit,
-                            &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
-                    src = tmp;
-                }
-            }
-
-            const Rect transformedBounds(mLayer.getTransformedBounds());
-            const copybit_rect_t& drect =
-                reinterpret_cast<const copybit_rect_t&>(transformedBounds);
-            const State& s(mLayer.drawingState());
-            region_iterator it(clip);
-
-            // pick the right orientation for this buffer
-            int orientation = mLayer.getOrientation();
-            if (UNLIKELY(mBufferHeap.transform)) {
-                Transform rot90;
-                GraphicPlane::orientationToTransfrom(
-                        ISurfaceComposer::eOrientation90, 0, 0, &rot90);
-                const Transform& planeTransform(mLayer.graphicPlane(0).transform());
-                const Layer::State& s(mLayer.drawingState());
-                Transform tr(planeTransform * s.transform * rot90);
-                orientation = tr.getOrientation();
-            }
-
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
-            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
-            err = copybit->stretch(copybit,
-                    &dst, &src.img, &drect, &src.crop, &it);
-            if (err != NO_ERROR) {
-                LOGE("copybit failed (%s)", strerror(err));
-            }
-        }
+        err = mLayer.initializeEglImage(graphicBuffer, &mTexture);
     }
 #endif
-    
-    if (!copybit || err) 
-    {
+    else {
+        err = INVALID_OPERATION;
+    }
+
+    if (err != NO_ERROR) {
         // OpenGL fall-back
-        if (UNLIKELY(mTexture.name == -1LU)) {
-            mTexture.name = mLayer.createTexture();
-        }
         GLuint w = 0;
         GLuint h = 0;
         GGLSurface t;
@@ -549,11 +450,11 @@
         t.data = (GGLubyte*)src.img.base;
         const Region dirty(Rect(t.width, t.height));
         mLayer.loadTexture(&mTexture, dirty, t);
-        mTexture.transform = mBufferHeap.transform;
-        mLayer.drawWithOpenGL(clip, mTexture);
     }
-}
 
+    mTexture.transform = mBufferHeap.transform;
+    mLayer.drawWithOpenGL(clip, mTexture);
+}
 
 // ---------------------------------------------------------------------------
 
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 5eb472c..438b711 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -132,7 +132,6 @@
         size_t                          mBufferSize;
         mutable sp<GraphicBuffer>       mTempBitmap;
         mutable LayerBase::Texture      mTexture;
-        copybit_device_t*               mBlitEngine;
     };
     
     class OverlaySource : public Source {
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 538dc77..fd61e30 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -55,8 +55,8 @@
     sHeight = h;
     sUseTexture = false;
     
-#ifdef DIM_WITH_TEXTURE
-    
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
+
 #warning "using a texture to implement LayerDim"
     
     /* On some h/w like msm7K, it is faster to use a texture because the
@@ -69,7 +69,6 @@
     uint32_t flags = hw.getFlags();
 
     if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
-        // TODO: api to pass the usage flags
         sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
                  GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                  GraphicBuffer::USAGE_HW_TEXTURE);
@@ -123,7 +122,7 @@
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
         glColor4x(0, 0, 0, alpha);
         
-#ifdef DIM_WITH_TEXTURE
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
         if (sUseTexture) {
             glBindTexture(GL_TEXTURE_2D, sTexId);
             glEnable(GL_TEXTURE_2D);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 1cf20d7..efe2d78 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -37,7 +37,7 @@
 // ===========================================================================
 
 GraphicBuffer::GraphicBuffer()
-    : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     width  = 
@@ -50,7 +50,7 @@
 
 GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, 
         PixelFormat reqFormat, uint32_t reqUsage)
-    : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     width  = 
@@ -62,8 +62,23 @@
     mInitCheck = initSize(w, h, reqFormat, reqUsage);
 }
 
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+        PixelFormat inFormat, uint32_t inUsage,
+        uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
+    : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+      mBufferMapper(GraphicBufferMapper::get()),
+      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
+{
+    width  = w;
+    height = h;
+    stride = inStride;
+    format = inFormat;
+    usage  = inUsage;
+    handle = inHandle;
+}
+
 GraphicBuffer::GraphicBuffer(const Parcel& data) 
-    : BASE(), mOwner(true), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     // we own the handle in this case
@@ -83,10 +98,10 @@
 GraphicBuffer::~GraphicBuffer()
 {
     if (handle) {
-        if (mOwner) {
+        if (mOwner == ownHandle) {
             native_handle_close(handle);
             native_handle_delete(const_cast<native_handle*>(handle));
-        } else {
+        } else if (mOwner == ownData) {
             GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
             allocator.free(handle);
         }
@@ -106,6 +121,9 @@
 status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
         uint32_t reqUsage)
 {
+    if (mOwner != ownData)
+        return INVALID_OPERATION;
+
     if (handle) {
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 35f0409..e1e09b9 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -19,10 +19,12 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.util.Log;
 
 import java.io.IOException;
 import java.lang.IllegalStateException;
+import java.util.LinkedList;
 
 /**
  * Plays a series of audio URIs, but does all the hard work on another thread
@@ -31,14 +33,15 @@
 public class AsyncPlayer {
     private static final int PLAY = 1;
     private static final int STOP = 2;
+    private static final boolean mDebug = false;
 
     private static final class Command {
-        Command next;
         int code;
         Context context;
         Uri uri;
         boolean looping;
         int stream;
+        long requestTime;
 
         public String toString() {
             return "{ code=" + code + " looping=" + looping + " stream=" + stream
@@ -46,6 +49,36 @@
         }
     }
 
+    private LinkedList<Command> mCmdQueue = new LinkedList();
+
+    private void startSound(Command cmd) {
+        // Preparing can be slow, so if there is something else
+        // is playing, let it continue until we're done, so there
+        // is less of a glitch.
+        try {
+            if (mDebug) Log.d(mTag, "Starting playback");
+            MediaPlayer player = new MediaPlayer();
+            player.setAudioStreamType(cmd.stream);
+            player.setDataSource(cmd.context, cmd.uri);
+            player.setLooping(cmd.looping);
+            player.prepare();
+            player.start();
+            if (mPlayer != null) {
+                mPlayer.release();
+            }
+            mPlayer = player;
+            long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+            if (delay > 1000) {
+                Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
+            }
+        }
+        catch (IOException e) {
+            Log.w(mTag, "error loading sound for " + cmd.uri, e);
+        } catch (IllegalStateException e) {
+            Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
+        }
+    }
+
     private final class Thread extends java.lang.Thread {
         Thread() {
             super("AsyncPlayer-" + mTag);
@@ -55,41 +88,23 @@
             while (true) {
                 Command cmd = null;
 
-                synchronized (mLock) {
-                    if (mHead != null) {
-                        cmd = mHead;
-                        mHead = cmd.next;
-                        if (mTail == cmd) {
-                            mTail = null;
-                        }
-                    }
+                synchronized (mCmdQueue) {
+                    if (mDebug) Log.d(mTag, "RemoveFirst");
+                    cmd = mCmdQueue.removeFirst();
                 }
 
                 switch (cmd.code) {
                 case PLAY:
-                    try {
-                        // Preparing can be slow, so if there is something else
-                        // is playing, let it continue until we're done, so there
-                        // is less of a glitch.
-                        MediaPlayer player = new MediaPlayer();
-                        player.setAudioStreamType(cmd.stream);
-                        player.setDataSource(cmd.context, cmd.uri);
-                        player.setLooping(cmd.looping);
-                        player.prepare();
-                        player.start();
-                        if (mPlayer != null) {
-                            mPlayer.release();
-                        }
-                        mPlayer = player;
-                    }
-                    catch (IOException e) {
-                        Log.w(mTag, "error loading sound for " + cmd.uri, e);
-                    } catch (IllegalStateException e) {
-                        Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
-                    }
+                    if (mDebug) Log.d(mTag, "PLAY");
+                    startSound(cmd);
                     break;
                 case STOP:
+                    if (mDebug) Log.d(mTag, "STOP");
                     if (mPlayer != null) {
+                        long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+                        if (delay > 1000) {
+                            Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
+                        }
                         mPlayer.stop();
                         mPlayer.release();
                         mPlayer = null;
@@ -99,8 +114,8 @@
                     break;
                 }
 
-                synchronized (mLock) {
-                    if (mHead == null) {
+                synchronized (mCmdQueue) {
+                    if (mCmdQueue.size() == 0) {
                         // nothing left to do, quit
                         // doing this check after we're done prevents the case where they
                         // added it during the operation from spawning two threads and
@@ -115,11 +130,8 @@
     }
 
     private String mTag;
-    private Command mHead;
-    private Command mTail;
     private Thread mThread;
     private MediaPlayer mPlayer;
-    private Object mLock = new Object();
     private PowerManager.WakeLock mWakeLock;
 
     // The current state according to the caller.  Reality lags behind
@@ -154,12 +166,13 @@
      */
     public void play(Context context, Uri uri, boolean looping, int stream) {
         Command cmd = new Command();
+        cmd.requestTime = SystemClock.uptimeMillis();
         cmd.code = PLAY;
         cmd.context = context;
         cmd.uri = uri;
         cmd.looping = looping;
         cmd.stream = stream;
-        synchronized (mLock) {
+        synchronized (mCmdQueue) {
             enqueueLocked(cmd);
             mState = PLAY;
         }
@@ -170,11 +183,12 @@
      * at this point.  Calling this multiple times has no ill effects.
      */
     public void stop() {
-        synchronized (mLock) {
+        synchronized (mCmdQueue) {
             // This check allows stop to be called multiple times without starting
             // a thread that ends up doing nothing.
             if (mState != STOP) {
                 Command cmd = new Command();
+                cmd.requestTime = SystemClock.uptimeMillis();
                 cmd.code = STOP;
                 enqueueLocked(cmd);
                 mState = STOP;
@@ -183,12 +197,7 @@
     }
 
     private void enqueueLocked(Command cmd) {
-        if (mTail == null) {
-            mHead = cmd;
-        } else {
-            mTail.next = cmd;
-        }
-        mTail = cmd;
+        mCmdQueue.add(cmd);
         if (mThread == null) {
             acquireWakeLock();
             mThread = new Thread();
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index d90871e..58a0bba 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -959,10 +959,10 @@
     ///////////////////////////////////////////////////////////////////////////
 
     public class VolumeStreamState {
-        private final String mVolumeIndexSettingName;
-        private final String mLastAudibleVolumeIndexSettingName;
         private final int mStreamType;
 
+        private String mVolumeIndexSettingName;
+        private String mLastAudibleVolumeIndexSettingName;
         private int mIndexMax;
         private int mIndex;
         private int mLastAudibleIndex;
@@ -970,8 +970,7 @@
 
         private VolumeStreamState(String settingName, int streamType) {
 
-            mVolumeIndexSettingName = settingName;
-            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+            setVolumeIndexSettingName(settingName);
 
             mStreamType = streamType;
 
@@ -991,6 +990,11 @@
             mDeathHandlers = new ArrayList<VolumeDeathHandler>();
         }
 
+        public void setVolumeIndexSettingName(String settingName) {
+            mVolumeIndexSettingName = settingName;
+            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+        }
+
         public boolean adjustIndex(int deltaIndex) {
             return setIndex(mIndex + deltaIndex * 10, true);
         }
@@ -1370,11 +1374,17 @@
                     mNotificationsUseRingVolume = notificationsUseRingVolume;
                     if (mNotificationsUseRingVolume == 1) {
                         STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+                        mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
+                                System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]);
                     } else {
                         STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
+                        mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
+                                System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]);
                         // Persist notification volume volume as it was not persisted while aliased to ring volume
+                        //  and persist with no delay as there might be registered observers of the persisted
+                        //  notification volume.
                         sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
-                                SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY);
+                                SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
                     }
                 }
             }
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 2522656..9837845 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -25,6 +25,13 @@
 	primitives.cpp.arm	        \
 	vertex.cpp.arm
 
+LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+
 ifeq ($(TARGET_ARCH),arm)
 	LOCAL_SRC_FILES += fixed_asm.S iterators.S
 	LOCAL_CFLAGS += -fstrict-aliasing
@@ -38,15 +45,9 @@
 ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
     LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
     LOCAL_SRC_FILES += copybit.cpp
+    LOCAL_SHARED_LIBRARIES += libui
 endif
 
-LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_LDLIBS := -lpthread -ldl
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
 LOCAL_MODULE:= libGLES_android
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
index 73b2355..0c3d0ee 100644
--- a/opengl/libagl/copybit.cpp
+++ b/opengl/libagl/copybit.cpp
@@ -33,6 +33,10 @@
 #include <hardware/copybit.h>
 #include <private/ui/android_natives_priv.h>
 
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
 
 #define DEBUG_COPYBIT true
 
@@ -175,16 +179,6 @@
         dtdy /= screen_h;
     }
     dtdy = -dtdy; // see equation of dtdy above
-    if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
-            || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
-        // The requested scale is out of the range the hardware
-        // can support.
-        LOGD_IF(DEBUG_COPYBIT,
-                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
-                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", 
-                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
-        return false;
-    }
 
     // copybit doesn't say anything about filtering, so we can't
     // discriminate. On msm7k, copybit will always filter.
@@ -278,21 +272,93 @@
         return false;
     }
 
-
-    // LOGW("calling copybits");
-
     copybit_device_t* copybit = c->copybits.blitEngine;
+    copybit_image_t src;
+    buffer_handle_t source_hnd = textureObject->buffer->handle;
+    textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
+    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
+
+    /*
+     *  Below we perform extra passes needed to emulate things the h/w
+     * cannot do.
+     */
+
+    const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
+    const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
+
+    sp<GraphicBuffer> tempBitmap;
+
+    if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+        dtdy < maxScaleInv || dtdy > minScaleInv)
+    {
+        // The requested scale is out of the range the hardware
+        // can support.
+        LOGD_IF(DEBUG_COPYBIT,
+                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+
+        int32_t xscale=0x10000, yscale=0x10000;
+        if (dsdx > minScaleInv)         xscale = c->copybits.minScale;
+        else if (dsdx < maxScaleInv)    xscale = c->copybits.maxScale;
+        if (dtdy > minScaleInv)         yscale = c->copybits.minScale;
+        else if (dtdy < maxScaleInv)    yscale = c->copybits.maxScale;
+        dsdx = gglMulx(dsdx, xscale);
+        dtdy = gglMulx(dtdy, yscale);
+
+        /* we handle only one step of resizing below. Handling an arbitrary
+         * number is relatively easy (replace "if" above by "while"), but requires
+         * two intermediate buffers and so far we never had the need.
+         */
+
+        if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+            dtdy < maxScaleInv || dtdy > minScaleInv) {
+            LOGD_IF(DEBUG_COPYBIT,
+                    "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+                    "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+                    dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+            return false;
+        }
+
+        const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
+        const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
+
+        LOGD_IF(DEBUG_COPYBIT,
+                "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
+                xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
+
+        tempBitmap = new GraphicBuffer(
+                    tmp_w, tmp_h, src.format,
+                    GraphicBuffer::USAGE_HW_2D);
+
+        status_t err = tempBitmap->initCheck();
+        if (err == NO_ERROR) {
+            copybit_image_t tmp_dst;
+            copybit_rect_t tmp_rect;
+            tmp_dst.w = tmp_w;
+            tmp_dst.h = tmp_h;
+            tmp_dst.format = src.format;
+            tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
+            tmp_rect.l = 0;
+            tmp_rect.t = 0;
+            tmp_rect.r = tmp_dst.w;
+            tmp_rect.b = tmp_dst.h;
+            region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b)));
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+            err = copybit->stretch(copybit,
+                    &tmp_dst, &src, &tmp_rect, &srect, &tmp_it);
+            src = tmp_dst;
+            srect = tmp_rect;
+        }
+    }
 
     copybit_image_t dst;
     buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
     textureToCopyBitImage(&cbSurface, cbSurface.format, target_hnd, &dst);
     copybit_rect_t drect = {x, y, x+w, y+h};
 
-    copybit_image_t src;
-    buffer_handle_t source_hnd = textureObject->buffer->handle;
-    textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
-    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
-
     copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
     copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
     copybit->set_parameter(copybit, COPYBIT_DITHER,
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
new file mode 100644
index 0000000..6ff248d
--- /dev/null
+++ b/opengl/tests/linetex/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	linetex.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-linetex
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
new file mode 100644
index 0000000..e62fe03
--- /dev/null
+++ b/opengl/tests/linetex/linetex.cpp
@@ -0,0 +1,117 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#define LOG_TAG "fillrate"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    EGLint configAttribs[] = {
+         EGL_DEPTH_SIZE, 0,
+         EGL_NONE
+     };
+     
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLContext context;
+     EGLConfig config;
+     EGLSurface surface;
+     EGLint w, h;
+     EGLDisplay dpy;
+
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+          
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
+     }
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     eglMakeCurrent(dpy, surface, surface, context);   
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+     
+     printf("w=%d, h=%d\n", w, h);
+     
+     glBindTexture(GL_TEXTURE_2D, 0);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+     glDisable(GL_DITHER);
+     glDisable(GL_BLEND);
+     glEnable(GL_TEXTURE_2D);
+     glColor4f(1,1,1,1);
+
+     const uint32_t t32[] = {
+             0xFFFFFFFF, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+             0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFF000000
+     };
+
+     const GLfloat vertices[4][2] = {
+             { 0,  0 },
+             { w,  h }
+     };
+
+     const GLfloat texCoords[4][2] = {
+             { 0,  0 },
+             { 1,  0 }
+     };
+
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+     glViewport(0, 0, w, h);
+     glMatrixMode(GL_PROJECTION);
+     glLoadIdentity();
+     glOrthof(0, w, 0, h, 0, 1);
+
+     glEnableClientState(GL_VERTEX_ARRAY);
+     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+     glVertexPointer(2, GL_FLOAT, 0, vertices);
+     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+     glClearColor(0,0,0,0);
+     glClear(GL_COLOR_BUFFER_BIT);
+     glDrawArrays(GL_LINES, 0, 2);
+     eglSwapBuffers(dpy, surface);
+
+     usleep(5*1000000);
+
+     eglTerminate(dpy);
+     
+     return 0;
+}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 5c4aa79..4bf606d 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -131,6 +131,8 @@
     static final boolean ANIMATE_KEYBOARD_LIGHTS = false;
     
     static final int ANIM_STEPS = 60/4;
+    // Slower animation for autobrightness changes
+    static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;
 
     // These magic numbers are the initial state of the LEDs at boot.  Ideally
     // we should read them from the driver, but our current hardware returns 0
@@ -156,7 +158,6 @@
     private int mProximityCount = 0;
     private int mPowerState;
     private boolean mOffBecauseOfUser;
-    private boolean mAnimatingScreenOff;
     private int mUserState;
     private boolean mKeyboardVisible = false;
     private boolean mUserActivityAllowed = true;
@@ -224,7 +225,7 @@
 
     // could be either static or controllable at runtime
     private static final boolean mSpew = false;
-    private static final boolean mDebugLightSensor = false;
+    private static final boolean mDebugLightSensor = (false || mSpew);
 
     /*
     static PrintStream mLog;
@@ -1230,7 +1231,6 @@
                         Log.d(TAG,
                               "preventScreenOn: turning on after a prior preventScreenOn(true)!");
                     }
-                    mAnimatingScreenOff = false;
                     int err = setScreenStateLocked(true);
                     if (err != 0) {
                         Log.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
@@ -1392,7 +1392,6 @@
                         reallyTurnScreenOn = false;
                     }
                     if (reallyTurnScreenOn) {
-                        mAnimatingScreenOff = false;
                         err = setScreenStateLocked(true);
                         long identity = Binder.clearCallingIdentity();
                         try {
@@ -1434,7 +1433,6 @@
                     if (!mScreenBrightness.animating) {
                         err = screenOffFinishedAnimatingLocked(becauseOfUser);
                     } else {
-                        mAnimatingScreenOff = true;
                         mOffBecauseOfUser = becauseOfUser;
                         err = 0;
                         mLastTouchDown = 0;
@@ -1452,7 +1450,6 @@
                 mTotalTouchDownTime, mTouchCycles);
         mLastTouchDown = 0;
         int err = setScreenStateLocked(false);
-        mAnimatingScreenOff = false;
         if (mScreenOnStartTime != 0) {
             mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
             mScreenOnStartTime = 0;
@@ -1825,9 +1822,6 @@
             return;
         }
 
-        if (mAnimatingScreenOff) {
-            return;
-        }
         if (false) {
             if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
                 Log.d(TAG, "userActivity !!!");//, new RuntimeException());
@@ -1845,6 +1839,11 @@
                         + " mProximitySensorActive=" + mProximitySensorActive
                         + " force=" + force);
             }
+            // ignore user activity if we are in the process of turning off the screen
+            if (mScreenBrightness.animating && mScreenBrightness.targetValue == 0) {
+                Log.d(TAG, "ignoring user activity while turning off screen");
+                return;
+            }
             if (mLastEventTime <= time || force) {
                 mLastEventTime = time;
                 if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
@@ -1925,27 +1924,45 @@
                     Log.d(TAG, "keyboardValue " + keyboardValue);
                 }
 
+                boolean startAnimation = false;
                 if (mScreenBrightnessOverride < 0) {
-                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
-                            lcdValue);
-                }
-                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
-                        buttonValue);
-                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
-                        keyboardValue);
-
-                // update our animation state
-                if (ANIMATE_SCREEN_LIGHTS) {
-                    mScreenBrightness.curValue = lcdValue;
-                    mScreenBrightness.animating = false;
+                    if (ANIMATE_SCREEN_LIGHTS) {
+                        if (mScreenBrightness.setTargetLocked(lcdValue,
+                                AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS,
+                                (int)mScreenBrightness.curValue)) {
+                            startAnimation = true;
+                        }
+                    } else {
+                        mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
+                                lcdValue);
+                    }
                 }
                 if (ANIMATE_BUTTON_LIGHTS) {
-                    mButtonBrightness.curValue = buttonValue;
-                    mButtonBrightness.animating = false;
+                    if (mButtonBrightness.setTargetLocked(buttonValue,
+                            AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                            (int)mButtonBrightness.curValue)) {
+                        startAnimation = true;
+                    }
+                } else {
+                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
+                            buttonValue);
                 }
                 if (ANIMATE_KEYBOARD_LIGHTS) {
-                    mKeyboardBrightness.curValue = keyboardValue;
-                    mKeyboardBrightness.animating = false;
+                    if (mKeyboardBrightness.setTargetLocked(keyboardValue,
+                            AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                            (int)mKeyboardBrightness.curValue)) {
+                        startAnimation = true;
+                    }
+                } else {
+                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
+                            keyboardValue);
+                }
+                if (startAnimation) {
+                    if (mDebugLightSensor) {
+                        Log.i(TAG, "lightSensorChangedLocked scheduling light animator");
+                    }
+                    mHandler.removeCallbacks(mLightAnimator);
+                    mHandler.post(mLightAnimator);
                 }
             }
         }
@@ -2041,6 +2058,7 @@
         if (mAutoBrightessEnabled != enabled) {
             mAutoBrightessEnabled = enabled;
             // reset computed brightness
+            mLightSensorValue = -1;
             mLightSensorBrightness = -1;
 
             if (mHasHardwareAutoBrightness) {
@@ -2263,14 +2281,17 @@
         if (ANIMATE_SCREEN_LIGHTS) {
             mScreenBrightness.curValue = brightness;
             mScreenBrightness.animating = false;
+            mScreenBrightness.targetValue = -1;
         }
         if (ANIMATE_KEYBOARD_LIGHTS) {
             mKeyboardBrightness.curValue = brightness;
             mKeyboardBrightness.animating = false;
+            mKeyboardBrightness.targetValue = -1;
         }
         if (ANIMATE_BUTTON_LIGHTS) {
             mButtonBrightness.curValue = brightness;
             mButtonBrightness.animating = false;
+            mButtonBrightness.targetValue = -1;
         }
     }
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
index 50b7c3f..9bc0962 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -74,6 +74,8 @@
 
         Intent intent = new Intent(runner.getContext(), ReliabilityTestActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync(
+            intent);
         //read from BufferedReader instead of populating a list in advance,
         //this will avoid excessive memory usage in case of a large list
         while((url = listReader.readLine()) != null) {
@@ -83,8 +85,6 @@
             start = System.currentTimeMillis();
             Log.v(LOGTAG, "Testing URL: " + url);
             FsUtils.updateTestStatus(TEST_STATUS_FILE, url);
-            ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync(
-                    intent);
             activity.reset();
             //use message to send new URL to avoid interacting with
             //WebView in non-UI thread
@@ -110,11 +110,11 @@
             if(runner.mLogtime) {
                 writeLoadTime(url, activity.getPageLoadTime());
             }
-            activity.finish();
             System.runFinalization();
             System.gc();
             System.gc();
         }
+        activity.finish();
         FsUtils.updateTestStatus(TEST_STATUS_FILE, TEST_DONE);
 //        activity.finish();
         listReader.close();