Merge "Report WPS overlap error" into honeycomb
diff --git a/api/current.xml b/api/current.xml
index 7e2ac7e..4989eba 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -137540,6 +137540,34 @@
 <parameter name="params" type="Params...">
 </parameter>
 </method>
+<method name="execute"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="runnable" type="java.lang.Runnable">
+</parameter>
+</method>
+<method name="executeOnExecutor"
+ return="android.os.AsyncTask&lt;Params, Progress, Result&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="exec" type="java.util.concurrent.Executor">
+</parameter>
+<parameter name="params" type="Params...">
+</parameter>
+</method>
 <method name="get"
  return="Result"
  abstract="false"
@@ -137672,6 +137700,16 @@
 <parameter name="values" type="Progress...">
 </parameter>
 </method>
+<field name="THREAD_POOL_EXECUTOR"
+ type="java.util.concurrent.ThreadPoolExecutor"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="AsyncTask.Status"
  extends="java.lang.Enum"
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 3212cba..d038cd6 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -18,7 +18,6 @@
 
 import android.util.Log;
 
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 
@@ -29,8 +28,6 @@
  * are then determined internally and the animation will call these functions as necessary to
  * animate the property.
  *
- * <p class="note"><b>Note:</b> Instances of this class hold only a {@link WeakReference}
- * to the target object.</p>
  * @see #setPropertyName(String)
  *
  */
@@ -38,7 +35,7 @@
     private static final boolean DBG = false;
 
     // The target object on which the property exists, set in the constructor
-    private WeakReference<Object> mTargetRef;
+    private Object mTarget;
 
     private String mPropertyName;
 
@@ -105,9 +102,6 @@
      * @return Method the method associated with mPropertyName.
      */
     private Method getPropertyFunction(String prefix, Class valueType) {
-        final Object target = mTargetRef == null ? null : mTargetRef.get();
-        if (target == null) return null;
-
         // TODO: faster implementation...
         Method returnVal = null;
         String firstLetter = mPropertyName.substring(0, 1);
@@ -120,7 +114,7 @@
             args[0] = valueType;
         }
         try {
-            returnVal = target.getClass().getMethod(setterName, args);
+            returnVal = mTarget.getClass().getMethod(setterName, args);
         } catch (NoSuchMethodException e) {
             Log.e("ObjectAnimator",
                     "Couldn't find setter/getter for property " + mPropertyName + ": " + e);
@@ -140,14 +134,13 @@
      * A constructor that takes a single property name and set of values. This constructor is
      * used in the simple case of animating a single property.
      *
-     * @param target The object whose property is to be animated. It will be weakly referenced
-     * from the newly-created ObjectAnimator. This object should have a public method on it called
-     * <code>setName()</code>, where <code>name</code> is the value of the <code>propertyName</code>
-     * parameter.
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
      * @param propertyName The name of the property being animated.
      */
     private ObjectAnimator(Object target, String propertyName) {
-        mTargetRef = new WeakReference<Object>(target);
+        mTarget = target;
         setPropertyName(propertyName);
     }
 
@@ -159,10 +152,9 @@
      * from the target object and property being animated). Therefore, there should typically
      * be two or more values.
      *
-     * @param target The object whose property is to be animated. It will be weakly referenced
-     * from the newly-created ObjectAnimator. This object should have a public method on it called
-     * <code>setName()</code>, where <code>name</code> is the value of the <code>propertyName</code>
-     * parameter.
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
      * @param propertyName The name of the property being animated.
      * @param values A set of values that the animation will animate between over time.
      * @return A ValueAnimator object that is set up to animate between the given values.
@@ -181,10 +173,9 @@
      * from the target object and property being animated). Therefore, there should typically
      * be two or more values.
      *
-     * @param target The object whose property is to be animated. It will be weakly referenced
-     * from the newly-created ObjectAnimator. This object should have a public method on it called
-     * <code>setName()</code>, where <code>name</code> is the value of the <code>propertyName</code>
-     * parameter.
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
      * @param propertyName The name of the property being animated.
      * @param values A set of values that the animation will animate between over time.
      * @return A ValueAnimator object that is set up to animate between the given values.
@@ -201,10 +192,10 @@
      * PropertyValuesHolder allows you to associate a set of animation values with a property
      * name.
      *
-     * @param target The object whose property is to be animated. It will be weakly referenced
-     * from the newly-created ObjectAnimator. This object should have public methods on it called
-     * <code>setName()</code>, where <code>name</code> is the name of the property passed in as the
-     * <code>propertyName</code> parameter for each of the PropertyValuesHolder objects.
+     * @param target The object whose property is to be animated. This object should
+     * have public methods on it called <code>setName()</code>, where <code>name</code> is
+     * the name of the property passed in as the <code>propertyName</code> parameter for
+     * each of the PropertyValuesHolder objects.
      * @param propertyName The name of the property being animated.
      * @param evaluator A TypeEvaluator that will be called on each animation frame to
      * provide the ncessry interpolation between the Object values to derive the animated
@@ -227,10 +218,10 @@
      * PropertyValuesHolder allows you to associate a set of animation values with a property
      * name.
      *
-     * @param target The object whose property is to be animated. It will be weakly referenced
-     * from the newly-created ObjectAnimator. This object should have public methods on it called
-     * <code>setName()</code>, where <code>name</code> is the name of the property passed in as the
-     * <code>propertyName</code> parameter for each of the PropertyValuesHolder objects.
+     * @param target The object whose property is to be animated. This object should
+     * have public methods on it called <code>setName()</code>, where <code>name</code> is
+     * the name of the property passed in as the <code>propertyName</code> parameter for
+     * each of the PropertyValuesHolder objects.
      * @param values A set of PropertyValuesHolder objects whose values will be animated
      * between over time.
      * @return A ValueAnimator object that is set up to animate between the given values.
@@ -238,7 +229,7 @@
     public static ObjectAnimator ofPropertyValuesHolder(Object target,
             PropertyValuesHolder... values) {
         ObjectAnimator anim = new ObjectAnimator();
-        anim.mTargetRef = new WeakReference<Object>(target);
+        anim.mTarget = target;
         anim.setValues(values);
         return anim;
     }
@@ -279,8 +270,7 @@
     @Override
     public void start() {
         if (DBG) {
-            final Object target = mTargetRef == null ? null : mTargetRef.get();
-            Log.d("ObjectAnimator", "Anim target, duration" + target + ", " + getDuration());
+            Log.d("ObjectAnimator", "Anim target, duration" + mTarget + ", " + getDuration());
             for (int i = 0; i < mValues.length; ++i) {
                 PropertyValuesHolder pvh = mValues[i];
                 ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
@@ -307,14 +297,11 @@
     @Override
     void initAnimation() {
         if (!mInitialized) {
-            final Object target = mTargetRef == null ? null : mTargetRef.get();
-            if (target == null) return;
-
             // mValueType may change due to setter/getter setup; do this before calling super.init(),
             // which uses mValueType to set up the default type evaluator.
             int numValues = mValues.length;
             for (int i = 0; i < numValues; ++i) {
-                mValues[i].setupSetterAndGetter(target);
+                mValues[i].setupSetterAndGetter(mTarget);
             }
             super.initAnimation();
         }
@@ -339,26 +326,23 @@
     /**
      * The target object whose property will be animated by this animation
      *
-     * @return The object being animated, or null if the object has been garbage collected.
+     * @return The object being animated
      */
     public Object getTarget() {
-        return mTargetRef == null ? null : mTargetRef.get();
+        return mTarget;
     }
 
     /**
-     * Sets the target object whose property will be animated by this animation. The target
-     * will be weakly referenced from this object.
+     * Sets the target object whose property will be animated by this animation
      *
      * @param target The object being animated
      */
     @Override
     public void setTarget(Object target) {
-        final Object currentTarget = mTargetRef == null ? null : mTargetRef.get();
-
-        if (currentTarget != target) {
-            mTargetRef = new WeakReference<Object>(target);
-            if (currentTarget != null && target != null
-                    && currentTarget.getClass() == target.getClass()) {
+        if (mTarget != target) {
+            final Object oldTarget = mTarget;
+            mTarget = target;
+            if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
                 return;
             }
             // New target type should cause re-initialization prior to starting
@@ -368,25 +352,19 @@
 
     @Override
     public void setupStartValues() {
-        final Object target = mTargetRef == null ? null : mTargetRef.get();
-        if (target == null) return;
-
         initAnimation();
         int numValues = mValues.length;
         for (int i = 0; i < numValues; ++i) {
-            mValues[i].setupStartValue(target);
+            mValues[i].setupStartValue(mTarget);
         }
     }
 
     @Override
     public void setupEndValues() {
-        final Object target = mTargetRef == null ? null : mTargetRef.get();
-        if (target == null) return;
-
         initAnimation();
         int numValues = mValues.length;
         for (int i = 0; i < numValues; ++i) {
-            mValues[i].setupEndValue(target);
+            mValues[i].setupEndValue(mTarget);
         }
     }
 
@@ -405,13 +383,9 @@
     @Override
     void animateValue(float fraction) {
         super.animateValue(fraction);
-
-        final Object target = mTargetRef == null ? null : mTargetRef.get();
-        if (target == null) return;
-
         int numValues = mValues.length;
         for (int i = 0; i < numValues; ++i) {
-            mValues[i].setAnimatedValue(target);
+            mValues[i].setAnimatedValue(mTarget);
         }
     }
 
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 17131d2..2d95781 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -281,9 +281,11 @@
      * Value for {@link #flags}: Set to true if the application has been
      * installed using the forward lock option.
      *
+     * NOTE: DO NOT CHANGE THIS VALUE!  It is saved in packages.xml.
+     * 
      * {@hide}
      */
-    public static final int FLAG_FORWARD_LOCK = 1<<30;
+    public static final int FLAG_FORWARD_LOCK = 1<<29;
 
     /**
      * Value for {@link #flags}: set to <code>true</code> if the application
@@ -296,7 +298,7 @@
      *
      * {@hide}
      */
-    public static final int FLAG_CANT_SAVE_STATE = 1<<29;
+    public static final int FLAG_CANT_SAVE_STATE = 1<<28;
 
     /**
      * Flags associated with the application.  Any combination of
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 9f7e31c..5a35eb0 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -16,9 +16,11 @@
 
 package android.os;
 
+import java.util.ArrayDeque;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -151,8 +153,6 @@
     private static final int MAXIMUM_POOL_SIZE = 128;
     private static final int KEEP_ALIVE = 1;
 
-    private static final BlockingQueue<Runnable> sWorkQueue =
-            new LinkedBlockingQueue<Runnable>(10);
 
     private static final ThreadFactory sThreadFactory = new ThreadFactory() {
         private final AtomicInteger mCount = new AtomicInteger(1);
@@ -162,8 +162,17 @@
         }
     };
 
-    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
-            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
+    private static final BlockingQueue<Runnable> sPoolWorkQueue =
+            new LinkedBlockingQueue<Runnable>(10);
+
+    /**
+     * A {@link ThreadPoolExecutor} that can be used to execute tasks in parallel.
+     */
+    public static final ThreadPoolExecutor THREAD_POOL_EXECUTOR
+            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
+                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
+
+    private static final SerialExecutor sSerialExecutor = new SerialExecutor();
 
     private static final int MESSAGE_POST_RESULT = 0x1;
     private static final int MESSAGE_POST_PROGRESS = 0x2;
@@ -177,6 +186,32 @@
     
     private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
 
+    private static class SerialExecutor implements Executor {
+        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
+        Runnable mActive;
+
+        public synchronized void execute(final Runnable r) {
+            mTasks.offer(new Runnable() {
+                public void run() {
+                    try {
+                        r.run();
+                    } finally {
+                        scheduleNext();
+                    }
+                }
+            });
+            if (mActive == null) {
+                scheduleNext();
+            }
+        }
+
+        protected synchronized void scheduleNext() {
+            if ((mActive = mTasks.poll()) != null) {
+                THREAD_POOL_EXECUTOR.execute(mActive);
+            }
+        }
+    }
+
     /**
      * Indicates the current status of the task. Each status will be set only once
      * during the lifetime of a task.
@@ -433,7 +468,11 @@
 
     /**
      * Executes the task with the specified parameters. The task returns
-     * itself (this) so that the caller can keep a reference to it.
+     * itself (this) so that the caller can keep a reference to it.  The tasks
+     * started by all invocations of this method in a given process are run
+     * sequentially.  Call the executeOnExecutor(Executor,Params...)
+     * with a custom {@link Executor} to have finer grained control over how the
+     * tasks are run.
      *
      * This method must be invoked on the UI thread.
      *
@@ -445,6 +484,26 @@
      *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
      */
     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
+        return executeOnExecutor(sSerialExecutor, params);
+    }
+
+    /**
+     * Executes the task with the specified parameters. The task returns
+     * itself (this) so that the caller can keep a reference to it.
+     *
+     * This method must be invoked on the UI thread.
+     *
+     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
+     *              convenient process-wide thread pool for tasks that are loosely coupled.
+     * @param params The parameters of the task.
+     *
+     * @return This instance of AsyncTask.
+     *
+     * @throws IllegalStateException If {@link #getStatus()} returns either
+     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
+     */
+    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
+            Params... params) {
         if (mStatus != Status.PENDING) {
             switch (mStatus) {
                 case RUNNING:
@@ -462,12 +521,20 @@
         onPreExecute();
 
         mWorker.mParams = params;
-        sExecutor.execute(mFuture);
+        exec.execute(mFuture);
 
         return this;
     }
 
     /**
+     * Schedules the {@link Runnable} in serial with the other AsyncTasks that were started
+     * with {@link #execute}.
+     */
+    public static void execute(Runnable runnable) {
+        sSerialExecutor.execute(runnable);
+    }
+
+    /**
      * This method can be invoked from {@link #doInBackground} to
      * publish updates on the UI thread while the background computation is
      * still running. Each call to this method will trigger the execution of
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ad9e6863..e228537 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1780,7 +1780,7 @@
     }
 
     void dispatchDetachedFromWindow() {
-        if (mView != null) {
+        if (mView != null && mView.mAttachInfo != null) {
             mView.dispatchDetachedFromWindow();
         }
 
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 3d21048..472a335 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -22,7 +22,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -212,6 +211,9 @@
                 .getDimensionPixelSize(com.android.internal.R.styleable.ExpandableListView_indicatorLeft, 0);
         mIndicatorRight = a
                 .getDimensionPixelSize(com.android.internal.R.styleable.ExpandableListView_indicatorRight, 0);
+        if (mIndicatorRight == 0) {
+            mIndicatorRight = mIndicatorLeft + mGroupIndicator.getIntrinsicWidth();
+        }
         mChildIndicatorLeft = a.getDimensionPixelSize(
                 com.android.internal.R.styleable.ExpandableListView_childIndicatorLeft, CHILD_INDICATOR_INHERIT);
         mChildIndicatorRight = a.getDimensionPixelSize(
diff --git a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
index 8a46546..4f5beff 100644
--- a/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout-xlarge/keyguard_screen_glogin_unlock.xml
@@ -27,12 +27,11 @@
         android:layout_height="0px"
         android:layout_weight="1"
         android:layout_above="@+id/emergencyCall">
-        <RelativeLayout 
+        <RelativeLayout
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-                >
-        
-            <TextView 
+            android:layout_height="match_parent">
+
+            <TextView
                 android:id="@+id/topHeader"
                 android:layout_width="match_parent"
                 android:layout_height="64dip"
@@ -43,7 +42,7 @@
                 android:drawableLeft="@drawable/ic_lock_idle_lock"
                 android:drawablePadding="5dip"
                 />
-        
+
             <!-- spacer below header -->
             <View
                 android:id="@+id/spacerTop"
@@ -51,7 +50,7 @@
                 android:layout_height="1dip"
                 android:layout_below="@id/topHeader"
                 android:background="@drawable/divider_horizontal_dark"/>
-        
+
             <TextView
                 android:id="@+id/instructions"
                 android:layout_width="match_parent"
@@ -62,7 +61,7 @@
                 android:textAppearance="?android:attr/textAppearanceSmall"
                 android:text="@android:string/lockscreen_glogin_instructions"
                 />
-        
+
             <EditText
                 android:id="@+id/login"
                 android:layout_width="match_parent"
@@ -74,7 +73,7 @@
                 android:hint="@android:string/lockscreen_glogin_username_hint"
                 android:inputType="textEmailAddress"
                 />
-        
+
             <EditText
                 android:id="@+id/password"
                 android:layout_width="match_parent"
@@ -88,11 +87,11 @@
                 android:nextFocusRight="@+id/ok"
                 android:nextFocusDown="@+id/ok"
                 />
-        
+
             <!-- ok below password, aligned to right of screen -->
             <Button
                 android:id="@+id/ok"
-                android:layout_width="85dip"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_below="@id/password"
                 android:layout_marginTop="7dip"
@@ -100,10 +99,10 @@
                 android:layout_alignParentRight="true"
                 android:text="@android:string/lockscreen_glogin_submit_button"
                 />
-        
+
         </RelativeLayout>
     </ScrollView>
-    
+
     <!-- spacer above emergency call -->
     <View
         android:layout_width="match_parent"
@@ -121,6 +120,7 @@
         android:drawableLeft="@drawable/ic_emergency"
         android:drawablePadding="8dip"
         android:text="@android:string/lockscreen_emergency_call"
+        android:visibility="gone"
         />
 
 </LinearLayout>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index f65b1f2..744d0d8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -114,7 +114,7 @@
                 ?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
-        <item name="expandableListPreferredItemIndicatorRight">33dip</item>
+        <item name="expandableListPreferredItemIndicatorRight">0dip</item>
         <item name="expandableListPreferredChildIndicatorLeft">
                 ?android:attr/expandableListPreferredItemIndicatorLeft</item>
         <item name="expandableListPreferredChildIndicatorRight">
@@ -816,7 +816,7 @@
                 ?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
-        <item name="expandableListPreferredItemIndicatorRight">33dip</item>
+        <item name="expandableListPreferredItemIndicatorRight">0dip</item>
         <item name="expandableListPreferredChildIndicatorLeft">
                 ?android:attr/expandableListPreferredItemIndicatorLeft</item>
         <item name="expandableListPreferredChildIndicatorRight">
@@ -1075,7 +1075,7 @@
                 ?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
-        <item name="expandableListPreferredItemIndicatorRight">33dip</item>
+        <item name="expandableListPreferredItemIndicatorRight">0dip</item>
         <item name="expandableListPreferredChildIndicatorLeft">
                 ?android:attr/expandableListPreferredItemIndicatorLeft</item>
         <item name="expandableListPreferredChildIndicatorRight">
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index bdd8e73..71ec760 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -37,6 +37,10 @@
 // Turn on to display vertex and tex coords data about 9patch objects
 // This flag requires DEBUG_PATCHES to be turned on
 #define DEBUG_PATCHES_VERTICES 0
+// Turn on to display vertex and tex coords data used by empty quads
+// in 9patch objects
+// This flag requires DEBUG_PATCHES to be turned on
+#define DEBUG_PATCHES_EMPTY_VERTICES 0
 
 // Turn on to display debug info about paths
 #define DEBUG_PATHS 0
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index cd2554e..e6bea78 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -29,10 +29,6 @@
 void LayerRenderer::prepare(bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
 
-#if RENDER_LAYERS_AS_REGIONS
-    mLayer->region.clear();
-#endif
-
     glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo);
     glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
 
@@ -78,6 +74,7 @@
             mLayer->meshIndices = NULL;
             mLayer->meshElementCount = 0;
         }
+        mLayer->region.clear();
         return;
     }
 
@@ -129,6 +126,8 @@
         indices[index + 4] = quad + 1;   // top-right
         indices[index + 5] = quad + 3;   // bottom-right
     }
+
+    mLayer->region.clear();
 #endif
 }
 
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index e5cb67b..77cbb80 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -212,7 +212,7 @@
         }
         float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth;
 
-        generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
+        bool valid = generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
 
         x1 = x2;
         u1 = (stepX + 0.5f) / bitmapWidth;
@@ -223,17 +223,22 @@
     generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
 }
 
-void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+bool Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2, uint32_t& quadCount) {
     const uint32_t oldQuadCount = quadCount;
-    const bool valid = x2 - x1 > 0.9999f && y2 - y1 > 0.9999f;
+    const bool valid = x2 >= x1 && y2 >= y1;
     if (valid) {
         quadCount++;
     }
 
     // Skip degenerate and transparent (empty) quads
     if (!valid || ((mColorKey >> oldQuadCount) & 0x1) == 1) {
-        return;
+#if DEBUG_PATCHES_EMPTY_VERTICES
+        PATCH_LOGD("    quad %d (empty)", oldQuadCount);
+        PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.2f, %.2f", x1, y1, u1, v1);
+        PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.2f, %.2f", x2, y2, u2, v2);
+#endif
+        return false;
     }
 
 #if RENDER_LAYERS_AS_REGIONS
@@ -262,6 +267,8 @@
     PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.2f, %.2f", x1, y1, u1, v1);
     PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.2f, %.2f", x2, y2, u2, v2);
 #endif
+
+    return true;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 0f0ffa2..45ce998 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -71,7 +71,7 @@
     void generateRow(TextureVertex*& vertex, float y1, float y2,
             float v1, float v2, float stretchX, float width, float bitmapWidth,
             uint32_t& quadCount);
-    void generateQuad(TextureVertex*& vertex,
+    bool generateQuad(TextureVertex*& vertex,
             float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2,
             uint32_t& quadCount);
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
index aa4cf2d..4615e1f 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/vertical_blur.rs
@@ -56,7 +56,7 @@
 }
 
 //sliao
-uchar3 convert2uchar3(float3 xyz);
+extern uchar3 __attribute__((overloadable)) convert2uchar3(float3 xyz);
 
 void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
     uchar4 *output = (uchar4 *)v_out;
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 2ed7774..6e4c22e 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -188,12 +188,7 @@
         isFirstUpload = true;
     }
 
-    GLenum target = (GLenum)getGLTarget();
-    if (target == GL_TEXTURE_2D) {
-        upload2DTexture(isFirstUpload, mPtr);
-    } else if (target == GL_TEXTURE_CUBE_MAP) {
-        uploadCubeTexture(isFirstUpload);
-    }
+    upload2DTexture(isFirstUpload);
 
     if (!(mUsageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
         freeScriptMemory();
@@ -202,6 +197,15 @@
     rsc->checkError("Allocation::uploadToTexture");
 }
 
+const static GLenum gFaceOrder[] = {
+    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+};
+
 void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
                                  uint32_t lod, RsAllocationCubemapFace face,
                                  uint32_t w, uint32_t h) {
@@ -210,10 +214,14 @@
     GLenum target = (GLenum)getGLTarget();
     glBindTexture(target, mTextureID);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    glTexSubImage2D(GL_TEXTURE_2D, lod, xoff, yoff, w, h, format, type, ptr);
+    GLenum t = GL_TEXTURE_2D;
+    if (mType->getDimFaces()) {
+        t = gFaceOrder[face];
+    }
+    glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr);
 }
 
-void Allocation::upload2DTexture(bool isFirstUpload, const void *ptr) {
+void Allocation::upload2DTexture(bool isFirstUpload) {
     GLenum type = mType->getElement()->getComponent().getGLType();
     GLenum format = mType->getElement()->getComponent().getGLFormat();
 
@@ -221,62 +229,29 @@
     glBindTexture(target, mTextureID);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
-    for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) {
-        const uint8_t *p = (const uint8_t *)ptr;
-        p += mType->getLODOffset(lod);
-
-        if (isFirstUpload) {
-            glTexImage2D(GL_TEXTURE_2D, lod, format,
-                         mType->getLODDimX(lod), mType->getLODDimY(lod),
-                         0, format, type, p);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0,
-                            mType->getLODDimX(lod), mType->getLODDimY(lod),
-                            format, type, p);
-        }
+    uint32_t faceCount = 1;
+    if (mType->getDimFaces()) {
+        faceCount = 6;
     }
 
-    if (mMipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
-#ifndef ANDROID_RS_BUILD_FOR_HOST
-        glGenerateMipmap(target);
-#endif //ANDROID_RS_BUILD_FOR_HOST
-    }
-}
-
-void Allocation::uploadCubeTexture(bool isFirstUpload) {
-    GLenum type = mType->getElement()->getComponent().getGLType();
-    GLenum format = mType->getElement()->getComponent().getGLFormat();
-
-    GLenum target = (GLenum)getGLTarget();
-    glBindTexture(target, mTextureID);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-    GLenum faceOrder[] = {
-        GL_TEXTURE_CUBE_MAP_POSITIVE_X,
-        GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
-        GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
-        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
-        GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
-        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
-    };
-
-    Adapter2D adapt(getContext(), this);
-    for (uint32_t face = 0; face < 6; face ++) {
-        adapt.setFace(face);
-
+    for (uint32_t face = 0; face < faceCount; face ++) {
         for (uint32_t lod = 0; lod < mType->getLODCount(); lod++) {
-            adapt.setLOD(lod);
+            const uint8_t *p = (const uint8_t *)mPtr;
+            p += mType->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
 
-            uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
+            GLenum t = GL_TEXTURE_2D;
+            if (mType->getDimFaces()) {
+                t = gFaceOrder[face];
+            }
 
             if (isFirstUpload) {
-                glTexImage2D(faceOrder[face], lod, format,
-                             adapt.getDimX(), adapt.getDimY(),
-                             0, format, type, ptr);
+                glTexImage2D(t, lod, format,
+                             mType->getLODDimX(lod), mType->getLODDimY(lod),
+                             0, format, type, p);
             } else {
-                glTexSubImage2D(faceOrder[face], lod, 0, 0,
-                                adapt.getDimX(), adapt.getDimY(),
-                                format, type, ptr);
+                glTexSubImage2D(t, lod, 0, 0,
+                                mType->getLODDimX(lod), mType->getLODDimY(lod),
+                                format, type, p);
             }
         }
     }
@@ -364,7 +339,7 @@
     if (mPtr) {
         const uint8_t *src = static_cast<const uint8_t *>(data);
         uint8_t *dst = static_cast<uint8_t *>(mPtr);
-        dst += mType->getLODOffset(lod, xoff, yoff);
+        dst += mType->getLODFaceOffset(lod, face, xoff, yoff);
 
         //LOGE("            %p  %p  %i  ", dst, src, eSize);
         for (uint32_t line=yoff; line < (yoff+h); line++) {
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index a160765..4f5d5a8 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -105,9 +105,6 @@
         return mMipmapControl != RS_ALLOCATION_MIPMAP_NONE;
     }
 
-    void upload2DTexture(bool isFirstUpload, const void *ptr);
-    void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
-                         uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h);
 
 protected:
     ObjectBaseRef<const Type> mType;
@@ -149,7 +146,9 @@
 
 private:
     void init(Context *rsc, const Type *);
-    void uploadCubeTexture(bool isFirstUpload);
+    void upload2DTexture(bool isFirstUpload);
+    void update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
+                         uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h);
 
     void allocScriptMemory();
     void freeScriptMemory();
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 0ecb18a..1ab2109 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -490,7 +490,8 @@
         if (bccLinkBC(s->mBccScript,
                       resName,
                       NULL /*rs_runtime_lib_bc*/,
-                      0 /*rs_runtime_lib_bc_size*/,
+                      1 /*rs_runtime_lib_bc_size*/
+                        /*"1" means skip buffer here, and let libbcc decide*/,
                       0) != 0) {
             LOGE("bcc: FAILS to link bitcode");
             // Handle Fatal Error
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 670ea33..d7b5f12 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -132,6 +132,17 @@
     return offset;
 }
 
+uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const {
+    uint32_t offset = mLODs[lod].mOffset;
+    offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
+
+    if (face != 0) {
+        uint32_t faceOffset = getSizeBytes() / 6;
+        offset += faceOffset * face;
+    }
+    return offset;
+}
+
 void Type::dumpLOGV(const char *prefix) const {
     char buf[1024];
     ObjectBase::dumpLOGV(prefix);
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 34498f0..90ae039 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -44,12 +44,14 @@
     uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
     uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
     uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
-    uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
 
+    uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
     uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
     uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
     uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
 
+    uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const;
+
     uint32_t getLODCount() const {return mLODCount;}
     bool getIsNp2() const;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
index da60f0d..1b2fcad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.AsyncTask;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
@@ -78,15 +79,19 @@
 
     // TODO: Fix this racy API by adding something better to TelephonyManager or
     // ConnectivityService.
-    private void unsafe(boolean enabled) {
-        Settings.System.putInt(
-                mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON,
-                enabled ? 1 : 0);
-        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra("state", enabled);
-        mContext.sendBroadcast(intent);
+    private void unsafe(final boolean enabled) {
+        AsyncTask.execute(new Runnable() {
+                public void run() {
+                    Settings.System.putInt(
+                            mContext.getContentResolver(),
+                            Settings.System.AIRPLANE_MODE_ON,
+                            enabled ? 1 : 0);
+                    Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+                    intent.putExtra("state", enabled);
+                    mContext.sendBroadcast(intent);
+                }
+            });
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
index 866e5fc..b0a6d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.AsyncTask;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
@@ -45,7 +46,6 @@
     }
 
     public void onCheckedChanged(CompoundButton view, boolean checked) {
-        Slog.d(TAG, "onCheckedChanged checked=" + checked + " mLockRotation=" + mLockRotation);
         if (checked != mLockRotation) {
             setLockRotation(checked);
         }
@@ -56,18 +56,22 @@
         return 0 == Settings.System.getInt(cr, Settings.System.ACCELEROMETER_ROTATION, 0);
     }
 
-    private void setLockRotation(boolean locked) {
+    private void setLockRotation(final boolean locked) {
         mLockRotation = locked;
-        try {
-            IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService(
-                        Context.WINDOW_SERVICE));
-            ContentResolver cr = mContext.getContentResolver();
-            if (locked) {
-                wm.freezeRotation();
-            } else {
-                wm.thawRotation();
-            }
-        } catch (RemoteException exc) {
-        }
+        AsyncTask.execute(new Runnable() {
+                public void run() {
+                    try {
+                        IWindowManager wm = IWindowManager.Stub.asInterface(
+                                ServiceManager.getService(Context.WINDOW_SERVICE));
+                        ContentResolver cr = mContext.getContentResolver();
+                        if (locked) {
+                            wm.freezeRotation();
+                        } else {
+                            wm.thawRotation();
+                        }
+                    } catch (RemoteException exc) {
+                    }
+                }
+            });
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
index ca1d98f..521467a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.AsyncTask;
 import android.os.IPowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -79,11 +80,15 @@
         setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
                 : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
         if (!automatic) {
-            value = value + value + MINIMUM_BACKLIGHT;
-            setBrightness(value);
+            final int val = value + value + MINIMUM_BACKLIGHT;
+            setBrightness(val);
             if (!tracking) {
-                Settings.System.putInt(mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS, value);
+                AsyncTask.execute(new Runnable() {
+                        public void run() {
+                            Settings.System.putInt(mContext.getContentResolver(), 
+                                    Settings.System.SCREEN_BRIGHTNESS, val);
+                        }
+                    });
             }
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2a39322..6b559cf 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -191,9 +191,6 @@
     static final int APPLICATION_PANEL_SUBLAYER = 1;
     static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
     
-    // Debugging: set this to have the system act like there is no hard keyboard.
-    static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
-    
     static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
     static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -914,38 +911,44 @@
     }
     
     private int determineHiddenState(int mode, int hiddenValue, int visibleValue) {
-        if (KEYBOARD_ALWAYS_HIDDEN) {
-            return hiddenValue;
-        }
-        if (mLidOpen == LID_ABSENT) {
-            return visibleValue;
-        }
-
-        switch (mode) {
-            case 1:
-                return mLidOpen == LID_OPEN ? visibleValue : hiddenValue;
-            case 2:
-                return mLidOpen == LID_OPEN ? hiddenValue : visibleValue;
+        if (mLidOpen != LID_ABSENT) {
+            switch (mode) {
+                case 1:
+                    return mLidOpen == LID_OPEN ? visibleValue : hiddenValue;
+                case 2:
+                    return mLidOpen == LID_OPEN ? hiddenValue : visibleValue;
+            }
         }
         return visibleValue;
     }
-    
+
     /** {@inheritDoc} */
     public void adjustConfigurationLw(Configuration config) {
         readLidState();
+
         mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN);
-        config.hardKeyboardHidden = determineHiddenState(
-                mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES,
-                Configuration.HARDKEYBOARDHIDDEN_NO);
-        config.navigationHidden = determineHiddenState(
-                mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES,
-                Configuration.NAVIGATIONHIDDEN_NO);
-        config.keyboardHidden = (config.hardKeyboardHidden
-                        == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput)
-                ? Configuration.KEYBOARDHIDDEN_NO
-                : Configuration.KEYBOARDHIDDEN_YES;
+
+        if (config.keyboard == Configuration.KEYBOARD_NOKEYS) {
+            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
+        } else {
+            config.hardKeyboardHidden = determineHiddenState(mLidKeyboardAccessibility,
+                    Configuration.HARDKEYBOARDHIDDEN_YES, Configuration.HARDKEYBOARDHIDDEN_NO);
+        }
+
+        if (config.navigation == Configuration.NAVIGATION_NONAV) {
+            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES;
+        } else {
+            config.navigationHidden = determineHiddenState(mLidNavigationAccessibility,
+                    Configuration.NAVIGATIONHIDDEN_YES, Configuration.NAVIGATIONHIDDEN_NO);
+        }
+
+        if (mHasSoftInput || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
+            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
+        } else {
+            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
+        }
     }
-    
+
     /** {@inheritDoc} */
     public int windowTypeToLayerLw(int type) {
         if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index e73afa0..7099ab5 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -25,6 +25,16 @@
         android:hardwareAccelerated="true">
 
         <activity
+                android:name="SimplePatchActivity"
+                android:label="_SimplePatch"
+                android:theme="@android:style/Theme.Translucent.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="ViewLayersActivity"
                 android:label="_ViewLayers">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png b/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png
new file mode 100644
index 0000000..d5c3276
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_maximized.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png b/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png
new file mode 100644
index 0000000..4515b42
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-mdpi/expander_ic_minimized.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java
new file mode 100644
index 0000000..a9b4d1c
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SimplePatchActivity.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class SimplePatchActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(new PatchView(this));
+    }
+
+    private static class PatchView extends View {
+        private final Drawable mDrawable;
+
+        public PatchView(Context context) {
+            super(context);
+            setBackgroundColor(0xff000000);
+            mDrawable = context.getResources().getDrawable(R.drawable.expander_ic_minimized);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.save();
+            canvas.translate(200, 200);
+            mDrawable.setBounds(3, 0, 33, 64);
+            mDrawable.draw(canvas);
+            mDrawable.setBounds(63, 0, 94, 64);
+            mDrawable.draw(canvas);
+            canvas.restore();
+        }
+    }
+}