Merge "Trim OpenGLRenderer's memory usage whenever possible"
diff --git a/api/current.txt b/api/current.txt
index a1e55bd..8e5a6d2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1823,6 +1823,7 @@
     method public static java.lang.String feedbackTypeToString(int);
     method public static java.lang.String flagToString(int);
     method public boolean getCanRetrieveWindowContent();
+    method public java.lang.String getDescription();
     method public java.lang.String getId();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public java.lang.String getSettingsActivityName();
@@ -16702,6 +16703,7 @@
     field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
     field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version";
+    field public static final java.lang.String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
     field public static final java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country";
     field public static final java.lang.String TTS_DEFAULT_LANG = "tts_default_lang";
     field public static final java.lang.String TTS_DEFAULT_PITCH = "tts_default_pitch";
@@ -20492,6 +20494,14 @@
     ctor public Base64OutputStream(java.io.OutputStream, int);
   }
 
+  public final deprecated class Config {
+    field public static final deprecated boolean DEBUG = false;
+    field public static final deprecated boolean LOGD = true;
+    field public static final deprecated boolean LOGV = false;
+    field public static final deprecated boolean PROFILE = false;
+    field public static final deprecated boolean RELEASE = true;
+  }
+
   public class DebugUtils {
     method public static boolean isObjectSelected(java.lang.Object);
   }
@@ -20731,11 +20741,12 @@
     method public void set(T, V);
   }
 
-  public class SparseArray {
+  public class SparseArray implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
     method public void append(int, E);
     method public void clear();
+    method public android.util.SparseArray<E> clone();
     method public void delete(int);
     method public E get(int);
     method public E get(int, E);
@@ -20750,11 +20761,12 @@
     method public E valueAt(int);
   }
 
-  public class SparseBooleanArray {
+  public class SparseBooleanArray implements java.lang.Cloneable {
     ctor public SparseBooleanArray();
     ctor public SparseBooleanArray(int);
     method public void append(int, boolean);
     method public void clear();
+    method public android.util.SparseBooleanArray clone();
     method public void delete(int);
     method public boolean get(int);
     method public boolean get(int, boolean);
@@ -20766,11 +20778,12 @@
     method public boolean valueAt(int);
   }
 
-  public class SparseIntArray {
+  public class SparseIntArray implements java.lang.Cloneable {
     ctor public SparseIntArray();
     ctor public SparseIntArray(int);
     method public void append(int, int);
     method public void clear();
+    method public android.util.SparseIntArray clone();
     method public void delete(int);
     method public int get(int);
     method public int get(int, int);
@@ -22034,9 +22047,12 @@
     method public android.graphics.SurfaceTexture getSurfaceTexture();
     method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
     method public boolean isAvailable();
+    method public android.graphics.Canvas lockCanvas();
+    method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
     method protected final void onDraw(android.graphics.Canvas);
     method public void setOpaque(boolean);
     method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
+    method public void unlockCanvasAndPost(android.graphics.Canvas);
   }
 
   public static abstract interface TextureView.SurfaceTextureListener {
@@ -23265,6 +23281,7 @@
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
     method public void interrupt();
     method public boolean isEnabled();
+    method public boolean isTouchExplorationEnabled();
     method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
     method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
   }
@@ -23301,6 +23318,7 @@
     method public boolean isSelected();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain();
+    method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean performAction(int);
     method public void recycle();
     method public void setBoundsInParent(android.graphics.Rect);
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 5f40f25..a09607a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -171,6 +171,11 @@
     private boolean mCanRetrieveWindowContent;
 
     /**
+     * Description of the accessibility service.
+     */
+    private String mDescription;
+
+    /**
      * Creates a new instance.
      */
     public AccessibilityServiceInfo() {
@@ -240,6 +245,8 @@
             mCanRetrieveWindowContent = asAttributes.getBoolean(
                     com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
                     false);
+            mDescription = asAttributes.getString(
+                    com.android.internal.R.styleable.AccessibilityService_description);
             asAttributes.recycle();
         } catch (NameNotFoundException e) {
             throw new XmlPullParserException( "Unable to create context for: "
@@ -313,6 +320,18 @@
     }
 
     /**
+     * Description of the accessibility service.
+     * <p>
+     *    <strong>Statically set from
+     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+     * </p>
+     * @return The description.
+     */
+    public String getDescription() {
+        return mDescription;
+    }
+
+    /**
      * {@inheritDoc}
      */
     public int describeContents() {
@@ -329,6 +348,7 @@
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
         parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+        parcel.writeString(mDescription);
     }
 
     private void initFromParcel(Parcel parcel) {
@@ -341,6 +361,7 @@
         mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
         mCanRetrieveWindowContent = (parcel.readInt() == 1);
+        mDescription = parcel.readString();
     }
 
     @Override
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 12a4dbb..06d18ec 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -25,6 +25,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 
 /**
@@ -178,14 +179,17 @@
      * the transition. The reason for this is that a further layout event should cause
      * existing animations to stop where they are prior to starting new animations. So
      * we cache all of the current animations in this map for possible cancellation on
-     * another layout event.
+     * another layout event. LinkedHashMaps are used to preserve the order in which animations
+     * are inserted, so that we process events (such as setting up start values) in the same order.
      */
-    private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>();
-    private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>();
-    private final HashMap<View, Animator> currentAppearingAnimations =
+    private final HashMap<View, Animator> pendingAnimations =
             new HashMap<View, Animator>();
-    private final HashMap<View, Animator> currentDisappearingAnimations =
-            new HashMap<View, Animator>();
+    private final LinkedHashMap<View, Animator> currentChangingAnimations =
+            new LinkedHashMap<View, Animator>();
+    private final LinkedHashMap<View, Animator> currentAppearingAnimations =
+            new LinkedHashMap<View, Animator>();
+    private final LinkedHashMap<View, Animator> currentDisappearingAnimations =
+            new LinkedHashMap<View, Animator>();
 
     /**
      * This hashmap is used to track the listeners that have been added to the children of
@@ -547,7 +551,7 @@
     }
 
     /**
-     * This function sets up runs animations on all of the views that change during layout.
+     * This function sets up animations on all of the views that change during layout.
      * For every child in the parent, we create a change animation of the appropriate
      * type (appearing or disappearing) and ask it to populate its start values from its
      * target view. We add layout listeners to all child views and listen for changes. For
@@ -821,24 +825,24 @@
      */
     public void cancel() {
         if (currentChangingAnimations.size() > 0) {
-            HashMap<View, Animator> currentAnimCopy =
-                    (HashMap<View, Animator>) currentChangingAnimations.clone();
+            LinkedHashMap<View, Animator> currentAnimCopy =
+                    (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
             for (Animator anim : currentAnimCopy.values()) {
                 anim.cancel();
             }
             currentChangingAnimations.clear();
         }
         if (currentAppearingAnimations.size() > 0) {
-            HashMap<View, Animator> currentAnimCopy =
-                    (HashMap<View, Animator>) currentAppearingAnimations.clone();
+            LinkedHashMap<View, Animator> currentAnimCopy =
+                    (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
             for (Animator anim : currentAnimCopy.values()) {
                 anim.end();
             }
             currentAppearingAnimations.clear();
         }
         if (currentDisappearingAnimations.size() > 0) {
-            HashMap<View, Animator> currentAnimCopy =
-                    (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+            LinkedHashMap<View, Animator> currentAnimCopy =
+                    (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
             for (Animator anim : currentAnimCopy.values()) {
                 anim.end();
             }
@@ -859,8 +863,8 @@
             case CHANGE_APPEARING:
             case CHANGE_DISAPPEARING:
                 if (currentChangingAnimations.size() > 0) {
-                    HashMap<View, Animator> currentAnimCopy =
-                            (HashMap<View, Animator>) currentChangingAnimations.clone();
+                    LinkedHashMap<View, Animator> currentAnimCopy =
+                            (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
                     for (Animator anim : currentAnimCopy.values()) {
                         anim.cancel();
                     }
@@ -869,8 +873,8 @@
                 break;
             case APPEARING:
                 if (currentAppearingAnimations.size() > 0) {
-                    HashMap<View, Animator> currentAnimCopy =
-                            (HashMap<View, Animator>) currentAppearingAnimations.clone();
+                    LinkedHashMap<View, Animator> currentAnimCopy =
+                            (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
                     for (Animator anim : currentAnimCopy.values()) {
                         anim.end();
                     }
@@ -879,8 +883,8 @@
                 break;
             case DISAPPEARING:
                 if (currentDisappearingAnimations.size() > 0) {
-                    HashMap<View, Animator> currentAnimCopy =
-                            (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+                    LinkedHashMap<View, Animator> currentAnimCopy =
+                            (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
                     for (Animator anim : currentAnimCopy.values()) {
                         anim.end();
                     }
@@ -1113,4 +1117,4 @@
                 View view, int transitionType);
     }
 
-}
\ No newline at end of file
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 67d200c..b548623 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -409,9 +409,10 @@
 
     /**
      * Sets the current USB function.
+     * If function is null, then the current function is set to the default function.
      *
-     * @param function name of the USB function
-     * @param makeDefault true if this should be set as the default
+     * @param function name of the USB function, or null to restore the default function
+     * @param makeDefault true if the function should be set as the new default function
      *
      * {@hide}
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23b53ae..34699e2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2683,6 +2683,13 @@
         public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
 
         /**
+         * If touch exploration is requested. Touch exploration is enabled if it is
+         * requested by this setting, accessibility is enabled and there is at least
+         * one enabled accessibility serivce that provides spoken feedback.
+         */
+        public static final String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
+
+        /**
          * List of the enabled accessibility providers.
          */
         public static final String ENABLED_ACCESSIBILITY_SERVICES =
diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java
new file mode 100644
index 0000000..70dc9aa
--- /dev/null
+++ b/core/java/android/util/Config.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.util;
+
+/**
+ * @deprecated This class is not useful, it just returns the same value for
+ * all constants, and has always done this.  Do not use it.
+ */
+@Deprecated
+public final class Config {
+    /** @hide */ public Config() {}
+
+    /**
+     * @deprecated Always false.
+     */
+    @Deprecated
+    public static final boolean DEBUG = false;
+
+    /**
+     * @deprecated Always true.
+     */
+    @Deprecated
+    public static final boolean RELEASE = true;
+
+    /**
+     * @deprecated Always false.
+     */
+    @Deprecated
+    public static final boolean PROFILE = false;
+
+    /**
+     * @deprecated Always false.
+     */
+    @Deprecated
+    public static final boolean LOGV = false;
+
+    /**
+     * @deprecated Always true.
+     */
+    @Deprecated
+    public static final boolean LOGD = true;
+}
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 132b595..09ce8e4 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -196,6 +196,12 @@
     private int pos = 0;
     private int limit = 0;
 
+    /*
+     * The offset of the first character in the buffer.
+     */
+    private int bufferStartLine = 1;
+    private int bufferStartColumn = 1;
+
     private final List<JsonScope> stack = new ArrayList<JsonScope>();
     {
         push(JsonScope.EMPTY_DOCUMENT);
@@ -711,6 +717,16 @@
      * false.
      */
     private boolean fillBuffer(int minimum) throws IOException {
+        // Before clobbering the old characters, update where buffer starts
+        for (int i = 0; i < pos; i++) {
+            if (buffer[i] == '\n') {
+                bufferStartLine++;
+                bufferStartColumn = 1;
+            } else {
+                bufferStartColumn++;
+            }
+        }
+
         if (limit != pos) {
             limit -= pos;
             System.arraycopy(buffer, pos, buffer, 0, limit);
@@ -729,6 +745,28 @@
         return false;
     }
 
+    private int getLineNumber() {
+        int result = bufferStartLine;
+        for (int i = 0; i < pos; i++) {
+            if (buffer[i] == '\n') {
+                result++;
+            }
+        }
+        return result;
+    }
+
+    private int getColumnNumber() {
+        int result = bufferStartColumn;
+        for (int i = 0; i < pos; i++) {
+            if (buffer[i] == '\n') {
+                result = 1;
+            } else {
+                result++;
+            }
+        }
+        return result;
+    }
+
     private int nextNonWhitespace() throws IOException {
         while (pos < limit || fillBuffer(1)) {
             int c = buffer[pos++];
@@ -1107,7 +1145,8 @@
      * with this reader's content.
      */
     private IOException syntaxError(String message) throws IOException {
-        throw new MalformedJsonException(message + " near " + getSnippet());
+        throw new MalformedJsonException(message
+                + " at line " + getLineNumber() + " column " + getColumnNumber());
     }
 
     private CharSequence getSnippet() {
diff --git a/core/java/android/util/JsonWriter.java b/core/java/android/util/JsonWriter.java
index 47e84c5..c1e6e40 100644
--- a/core/java/android/util/JsonWriter.java
+++ b/core/java/android/util/JsonWriter.java
@@ -407,6 +407,11 @@
              * quotation marks except for the characters that must be escaped:
              * quotation mark, reverse solidus, and the control characters
              * (U+0000 through U+001F)."
+             *
+             * We also escape '\u2028' and '\u2029', which JavaScript interprets
+             * as newline characters. This prevents eval() from failing with a
+             * syntax error.
+             * http://code.google.com/p/google-gson/issues/detail?id=341
              */
             switch (c) {
                 case '"':
@@ -435,6 +440,11 @@
                     out.write("\\f");
                     break;
 
+                case '\u2028':
+                case '\u2029':
+                    out.write(String.format("\\u%04x", (int) c));
+                    break;
+
                 default:
                     if (c <= 0x1F) {
                         out.write(String.format("\\u%04x", (int) c));
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 7fc43b9..7cf4579 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -23,10 +23,14 @@
  * there can be gaps in the indices.  It is intended to be more efficient
  * than using a HashMap to map Integers to Objects.
  */
-public class SparseArray<E> {
+public class SparseArray<E> implements Cloneable {
     private static final Object DELETED = new Object();
     private boolean mGarbage = false;
 
+    private int[] mKeys;
+    private Object[] mValues;
+    private int mSize;
+
     /**
      * Creates a new SparseArray containing no mappings.
      */
@@ -47,6 +51,20 @@
         mSize = 0;
     }
 
+    @Override
+    @SuppressWarnings("unchecked")
+    public SparseArray<E> clone() {
+        SparseArray<E> clone = null;
+        try {
+            clone = (SparseArray<E>) super.clone();
+            clone.mKeys = mKeys.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
     /**
      * Gets the Object mapped from the specified key, or <code>null</code>
      * if no such mapping has been made.
@@ -59,6 +77,7 @@
      * Gets the Object mapped from the specified key, or the specified Object
      * if no such mapping has been made.
      */
+    @SuppressWarnings("unchecked")
     public E get(int key, E valueIfKeyNotFound) {
         int i = binarySearch(mKeys, 0, mSize, key);
 
@@ -209,6 +228,7 @@
      * the value from the <code>index</code>th key-value mapping that this
      * SparseArray stores.  
      */
+    @SuppressWarnings("unchecked")
     public E valueAt(int index) {
         if (mGarbage) {
             gc();
@@ -331,20 +351,4 @@
         else
             return ~high;
     }
-
-    private void checkIntegrity() {
-        for (int i = 1; i < mSize; i++) {
-            if (mKeys[i] <= mKeys[i - 1]) {
-                for (int j = 0; j < mSize; j++) {
-                    Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
-                }
-
-                throw new RuntimeException();
-            }
-        }
-    }
-
-    private int[] mKeys;
-    private Object[] mValues;
-    private int mSize;
 }
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index f7799de..76c47c6 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -24,7 +24,7 @@
  * there can be gaps in the indices.  It is intended to be more efficient
  * than using a HashMap to map Integers to Booleans.
  */
-public class SparseBooleanArray {
+public class SparseBooleanArray implements Cloneable {
     /**
      * Creates a new SparseBooleanArray containing no mappings.
      */
@@ -45,6 +45,19 @@
         mSize = 0;
     }
 
+    @Override
+    public SparseBooleanArray clone() {
+        SparseBooleanArray clone = null;
+        try {
+            clone = (SparseBooleanArray) super.clone();
+            clone.mKeys = mKeys.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
     /**
      * Gets the boolean mapped from the specified key, or <code>false</code>
      * if no such mapping has been made.
@@ -227,18 +240,6 @@
             return ~high;
     }
 
-    private void checkIntegrity() {
-        for (int i = 1; i < mSize; i++) {
-            if (mKeys[i] <= mKeys[i - 1]) {
-                for (int j = 0; j < mSize; j++) {
-                    Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
-                }
-
-                throw new RuntimeException();
-            }
-        }
-    }
-
     private int[] mKeys;
     private boolean[] mValues;
     private int mSize;
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 9ab3b53..8d11177 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -23,7 +23,12 @@
  * there can be gaps in the indices.  It is intended to be more efficient
  * than using a HashMap to map Integers to Integers.
  */
-public class SparseIntArray {
+public class SparseIntArray implements Cloneable {
+
+    private int[] mKeys;
+    private int[] mValues;
+    private int mSize;
+
     /**
      * Creates a new SparseIntArray containing no mappings.
      */
@@ -44,6 +49,19 @@
         mSize = 0;
     }
 
+    @Override
+    public SparseIntArray clone() {
+        SparseIntArray clone = null;
+        try {
+            clone = (SparseIntArray) super.clone();
+            clone.mKeys = mKeys.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
     /**
      * Gets the int mapped from the specified key, or <code>0</code>
      * if no such mapping has been made.
@@ -232,20 +250,4 @@
         else
             return ~high;
     }
-
-    private void checkIntegrity() {
-        for (int i = 1; i < mSize; i++) {
-            if (mKeys[i] <= mKeys[i - 1]) {
-                for (int j = 0; j < mSize; j++) {
-                    Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
-                }
-
-                throw new RuntimeException();
-            }
-        }
-    }
-
-    private int[] mKeys;
-    private int[] mValues;
-    private int mSize;
 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index d656f31..96d6f09 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -20,6 +20,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -107,6 +108,14 @@
 
     private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
 
+    private Canvas mCanvas;
+    private int mSaveCount;
+
+    private final Object[] mNativeWindowLock = new Object[0];
+    // Used from native code, do not write!
+    @SuppressWarnings({"UnusedDeclaration"})
+    private int mNativeWindow;
+
     /**
      * Creates a new TextureView.
      * 
@@ -190,7 +199,11 @@
                 mListener.onSurfaceTextureDestroyed(mSurface);
             }
 
-            mLayer.destroy();            
+            synchronized (mNativeWindowLock) {
+                nDestroyNativeWindow();
+            }
+
+            mLayer.destroy();
             mSurface = null;
             mLayer = null;
         }
@@ -274,6 +287,7 @@
             mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
             mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
             nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+            nCreateNativeWindow(mSurface);            
 
             mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
                 @Override
@@ -431,6 +445,79 @@
     }
 
     /**
+     * <p>Start editing the pixels in the surface.  The returned Canvas can be used
+     * to draw into the surface's bitmap.  A null is returned if the surface has
+     * not been created or otherwise cannot be edited. You will usually need
+     * to implement
+     * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)}
+     * to find out when the Surface is available for use.</p>
+     * 
+     * <p>The content of the Surface is never preserved between unlockCanvas()
+     * and lockCanvas(), for this reason, every pixel within the Surface area
+     * must be written. The only exception to this rule is when a dirty
+     * rectangle is specified, in which case, non-dirty pixels will be
+     * preserved.</p>
+     * 
+     * @return A Canvas used to draw into the surface.
+     * 
+     * @see #lockCanvas(android.graphics.Rect) 
+     * @see #unlockCanvasAndPost(android.graphics.Canvas) 
+     */
+    public Canvas lockCanvas() {
+        return lockCanvas(null);
+    }
+
+    /**
+     * Just like {@link #lockCanvas()} but allows specification of a dirty
+     * rectangle. Every pixel within that rectangle must be written; however
+     * pixels outside the dirty rectangle will be preserved by the next call
+     * to lockCanvas().
+     * 
+     * @param dirty Area of the surface that will be modified.
+
+     * @return A Canvas used to draw into the surface.
+     * 
+     * @see #lockCanvas() 
+     * @see #unlockCanvasAndPost(android.graphics.Canvas) 
+     */
+    public Canvas lockCanvas(Rect dirty) {
+        if (!isAvailable()) return null;
+
+        if (mCanvas == null) {
+            mCanvas = new Canvas();
+        }
+
+        synchronized (mNativeWindowLock) {
+            nLockCanvas(mNativeWindow, mCanvas, dirty);
+        }
+        mSaveCount = mCanvas.save();
+
+        return mCanvas;
+    }
+
+    /**
+     * Finish editing pixels in the surface. After this call, the surface's
+     * current pixels will be shown on the screen, but its content is lost,
+     * in particular there is no guarantee that the content of the Surface
+     * will remain unchanged when lockCanvas() is called again.
+     * 
+     * @param canvas The Canvas previously returned by lockCanvas()
+     * 
+     * @see #lockCanvas()
+     * @see #lockCanvas(android.graphics.Rect) 
+     */
+    public void unlockCanvasAndPost(Canvas canvas) {
+        if (mCanvas != null && canvas == mCanvas) {
+            canvas.restoreToCount(mSaveCount);
+            mSaveCount = 0;
+
+            synchronized (mNativeWindowLock) {
+                nUnlockCanvasAndPost(mNativeWindow, mCanvas);
+            }
+        }
+    }
+
+    /**
      * Returns the {@link SurfaceTexture} used by this view. This method
      * may return null if the view is not attached to a window or if the surface
      * texture has not been initialized yet.
@@ -506,6 +593,12 @@
         public void onSurfaceTextureUpdated(SurfaceTexture surface);
     }
 
+    private native void nCreateNativeWindow(SurfaceTexture surface);
+    private native void nDestroyNativeWindow();
+
     private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
             int width, int height);
+
+    private static native void nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
+    private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 41b9e2d..4385c2f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9127,12 +9127,12 @@
                 // Start user padding override Left user padding. Otherwise, if Left user
                 // padding is not defined, use the default left padding. If Left user padding
                 // is defined, just use it.
-                if (mUserPaddingStart > 0) {
+                if (mUserPaddingStart >= 0) {
                     mUserPaddingLeft = mUserPaddingStart;
                 } else if (mUserPaddingLeft < 0) {
                     mUserPaddingLeft = mPaddingLeft;
                 }
-                if (mUserPaddingEnd > 0) {
+                if (mUserPaddingEnd >= 0) {
                     mUserPaddingRight = mUserPaddingEnd;
                 } else if (mUserPaddingRight < 0) {
                     mUserPaddingRight = mPaddingRight;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index ac86769..9be2a67 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -552,7 +552,8 @@
 
     /**
      * Returns a cached instance if such is available or a new one is
-     * initialized with from the given <code>event</code>.
+     * created. The returned instance is initialized from the given
+     * <code>event</code>.
      *
      * @param event The other event.
      * @return An instance.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 314b7ca..83c73cb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -71,7 +71,9 @@
 
     private static AccessibilityManager sInstance;
 
-    private static final int DO_SET_ENABLED = 10;
+    private static final int DO_SET_ACCESSIBILITY_ENABLED = 10;
+
+    private static final int DO_SET_TOUCH_EXPLORATION_ENABLED = 20;
 
     final IAccessibilityManager mService;
 
@@ -79,6 +81,8 @@
 
     boolean mIsEnabled;
 
+    boolean mIsTouchExplorationEnabled;
+
     final CopyOnWriteArrayList<AccessibilityStateChangeListener> mAccessibilityStateChangeListeners =
         new CopyOnWriteArrayList<AccessibilityStateChangeListener>();
 
@@ -97,7 +101,12 @@
 
     final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() {
         public void setEnabled(boolean enabled) {
-            mHandler.obtainMessage(DO_SET_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
+            mHandler.obtainMessage(DO_SET_ACCESSIBILITY_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
+        }
+
+        public void setTouchExplorationEnabled(boolean enabled) {
+            mHandler.obtainMessage(DO_SET_TOUCH_EXPLORATION_ENABLED,
+                    enabled ? 1 : 0, 0).sendToTarget();
         }
     };
 
@@ -110,9 +119,14 @@
         @Override
         public void handleMessage(Message message) {
             switch (message.what) {
-                case DO_SET_ENABLED :
-                    final boolean isEnabled = (message.arg1 == 1);
-                    setAccessibilityState(isEnabled);
+                case DO_SET_ACCESSIBILITY_ENABLED :
+                    final boolean isAccessibilityEnabled = (message.arg1 == 1);
+                    setAccessibilityState(isAccessibilityEnabled);
+                    return;
+                case DO_SET_TOUCH_EXPLORATION_ENABLED :
+                    synchronized (mHandler) {
+                        mIsTouchExplorationEnabled = (message.arg1 == 1);
+                    }
                     return;
                 default :
                     Log.w(LOG_TAG, "Unknown message type: " + message.what);
@@ -168,6 +182,17 @@
     }
 
     /**
+     * Returns if the touch exploration in the system is enabled.
+     *
+     * @return True if touch exploration is enabled, false otherwise.
+     */
+    public boolean isTouchExplorationEnabled() {
+        synchronized (mHandler) {
+            return mIsTouchExplorationEnabled;
+        }
+    }
+
+    /**
      * Returns the client interface this instance registers in
      * the centralized accessibility manager service.
      *
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 031c6ae..0e04471 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -120,7 +120,7 @@
     private CharSequence mText;
     private CharSequence mContentDescription;
 
-    private final SparseIntArray mChildAccessibilityIds = new SparseIntArray();
+    private SparseIntArray mChildAccessibilityIds = new SparseIntArray();
     private int mActions;
 
     private IAccessibilityServiceConnection mConnection;
@@ -873,6 +873,20 @@
     }
 
     /**
+     * Returns a cached instance if such is available or a new one is
+     * create. The returned instance is initialized from the given
+     * <code>info</code>.
+     *
+     * @param info The other info.
+     * @return An instance.
+     */
+    public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
+        AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
+        infoClone.init(info);
+        return infoClone;
+    }
+
+    /**
      * Return an instance back to be reused.
      * <p>
      * <strong>Note:</strong> You must not touch the object after calling this function.
@@ -945,6 +959,28 @@
     }
 
     /**
+     * Initializes this instance from another one.
+     *
+     * @param other The other instance.
+     */
+    private void init(AccessibilityNodeInfo other) {
+        mSealed = other.mSealed;
+        mConnection = other.mConnection;
+        mAccessibilityViewId = other.mAccessibilityViewId;
+        mParentAccessibilityViewId = other.mParentAccessibilityViewId;
+        mAccessibilityWindowId = other.mAccessibilityWindowId;
+        mBoundsInParent.set(other.mBoundsInParent);
+        mBoundsInScreen.set(other.mBoundsInScreen);
+        mPackageName = other.mPackageName;
+        mClassName = other.mClassName;
+        mText = other.mText;
+        mContentDescription = other.mContentDescription;
+        mActions= other.mActions;
+        mBooleanProperties = other.mBooleanProperties;
+        mChildAccessibilityIds = other.mChildAccessibilityIds.clone();
+    }
+
+    /**
      * Creates a new instance from a {@link Parcel}.
      *
      * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
@@ -994,6 +1030,7 @@
         mConnection = null;
         mAccessibilityViewId = View.NO_ID;
         mParentAccessibilityViewId = View.NO_ID;
+        mAccessibilityWindowId = View.NO_ID;
         mChildAccessibilityIds.clear();
         mBoundsInParent.set(0, 0, 0, 0);
         mBoundsInScreen.set(0, 0, 0, 0);
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 1eb60fc..4e69692 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -26,4 +26,5 @@
 
     void setEnabled(boolean enabled);
 
+    void setTouchExplorationEnabled(boolean enabled);
 }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index b9eb5ff..f82c61a 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -28,7 +28,7 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import com.android.internal.R.styleable;
+import com.android.internal.R;
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
@@ -167,7 +167,7 @@
     // Misc constants
 
     private static final String TAG = GridLayout.class.getName();
-    static final boolean DEBUG = false;
+    static boolean DEBUG = false;
     private static final int PRF = 1;
 
     // Defaults
@@ -178,19 +178,17 @@
     private static final boolean DEFAULT_ORDER_PRESERVED = false;
     private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
     private static final int DEFAULT_CONTAINER_MARGIN = 0;
-    private static final int DEFAULT_MARGIN = 8;
-    private static final int DEFAULT_CONTAINER_PADDING = 16;
     private static final int MAX_SIZE = 100000;
 
     // TypedArray indices
 
-    private static final int ORIENTATION = styleable.GridLayout_orientation;
-    private static final int ROW_COUNT = styleable.GridLayout_rowCount;
-    private static final int COLUMN_COUNT = styleable.GridLayout_columnCount;
-    private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins;
-    private static final int ALIGNMENT_MODE = styleable.GridLayout_alignmentMode;
-    private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved;
-    private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved;
+    private static final int ORIENTATION = R.styleable.GridLayout_orientation;
+    private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
+    private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
+    private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
+    private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
+    private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
+    private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
 
     // Instance variables
 
@@ -201,6 +199,7 @@
     private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
     private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
     private int mDefaultGravity = Gravity.NO_GRAVITY;
+    private int mDefaultGap;
 
     // Constructors
 
@@ -212,7 +211,8 @@
         if (DEBUG) {
             setWillNotDraw(false);
         }
-        TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout);
+        mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
         try {
             setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
             setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
@@ -382,7 +382,7 @@
     public void setUseDefaultMargins(boolean useDefaultMargins) {
         mUseDefaultMargins = useDefaultMargins;
         if (useDefaultMargins) {
-            int padding = DEFAULT_CONTAINER_PADDING;
+            int padding = mDefaultGap;
             setPadding(padding, padding, padding, padding);
         }
         requestLayout();
@@ -538,7 +538,7 @@
     }
 
     private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
-        return DEFAULT_MARGIN;
+        return mDefaultGap / 2;
     }
 
     private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
@@ -787,6 +787,12 @@
         invalidateStructure();
     }
 
+    @Override
+    public void removeAllViews() {
+        super.removeAllViews();
+        invalidateStructure();
+    }
+
     // Measurement
 
     private boolean isGone(View c) {
@@ -1596,8 +1602,8 @@
      * each cell group. The fundamental parameters associated with each cell group are
      * gathered into their vertical and horizontal components and stored
      * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
-     * {@link android.widget.GridLayout.Spec Specs} are immutable structures and may be shared between the layout
-     * parameters of different children.
+     * {@link android.widget.GridLayout.Spec Specs} are immutable structures
+     * and may be shared between the layout parameters of different children.
      * <p>
      * The row and column specs contain the leading and trailing indices along each axis
      * and together specify the four grid indices that delimit the cells of this cell group.
@@ -1667,24 +1673,25 @@
 
         // TypedArray indices
 
-        private static final int MARGIN = styleable.ViewGroup_MarginLayout_layout_margin;
-        private static final int LEFT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginLeft;
-        private static final int TOP_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginTop;
-        private static final int RIGHT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginRight;
+        private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin;
+        private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft;
+        private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop;
+        private static final int RIGHT_MARGIN =
+                R.styleable.ViewGroup_MarginLayout_layout_marginRight;
         private static final int BOTTOM_MARGIN =
-                styleable.ViewGroup_MarginLayout_layout_marginBottom;
+                R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
 
-        private static final int COLUMN = styleable.GridLayout_Layout_layout_column;
-        private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan;
+        private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
+        private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
         private static final int COLUMN_FLEXIBILITY =
-                styleable.GridLayout_Layout_layout_columnFlexibility;
+                R.styleable.GridLayout_Layout_layout_columnFlexibility;
 
-        private static final int ROW = styleable.GridLayout_Layout_layout_row;
-        private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan;
+        private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
+        private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
         private static final int ROW_FLEXIBILITY =
-                styleable.GridLayout_Layout_layout_rowFlexibility;
+                R.styleable.GridLayout_Layout_layout_rowFlexibility;
 
-        private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity;
+        private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
 
         // Instance variables
 
@@ -1804,7 +1811,8 @@
 
         // This method could be parametrized and moved into MarginLayout.
         private void reInitSuper(Context context, AttributeSet attrs) {
-            TypedArray a = context.obtainStyledAttributes(attrs, styleable.ViewGroup_MarginLayout);
+            TypedArray a =
+                    context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
             try {
                 int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
 
@@ -1840,7 +1848,7 @@
         }
 
         private void init(Context context, AttributeSet attrs, int defaultGravity) {
-            TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
             try {
                 int gravity = a.getInt(GRAVITY, defaultGravity);
 
@@ -2301,10 +2309,10 @@
      */
     @Deprecated
     public static class Group extends Spec {
-    /**
-     * @deprecated  Please replace with {@link #spec(int, int, Alignment)}
-     * @hide
-     */
+        /**
+         * @deprecated Please replace with {@link #spec(int, int, Alignment)}
+         * @hide
+         */
         @Deprecated
         public Group(int start, int size, Alignment alignment) {
             super(start, size, alignment, UNDEFINED_FLEXIBILITY);
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 942aa8a1..682c3c4 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -799,24 +799,6 @@
                 x, y, flags, paint);
     }
 
-    static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
-                                      jcharArray text, int index, int count,
-                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
-        jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
-        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
-    }
-
-    static void drawTextWithGlyphs__StringIIFFIPaint(JNIEnv* env, jobject,
-                                          SkCanvas* canvas, jstring text,
-                                          int start, int end,
-                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
-
-        const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
-        env->ReleaseStringChars(text, textArray);
-    }
-
     static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
             jfloat x, jfloat y, int flags, SkPaint* paint) {
         // TODO: need to suppress this code after the GL renderer is modified for not
@@ -833,16 +815,6 @@
         paint->setTextEncoding(oldEncoding);
     }
 
-    static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
-                                         jcharArray glyphs, int index, int count,
-                                         jfloat x, jfloat y, int flags, SkPaint* paint) {
-        jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
-
-        doDrawGlyphs(canvas, glyphArray, index, count, x, y, flags, paint);
-
-        env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
-    }
-
     static void drawTextRun___CIIIIFFIPaint(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
@@ -1044,12 +1016,6 @@
         (void*) SkCanvasGlue::drawText___CIIFFIPaint},
     {"native_drawText","(ILjava/lang/String;IIFFII)V",
         (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
-    {"native_drawTextWithGlyphs","(I[CIIFFII)V",
-        (void*) SkCanvasGlue::drawTextWithGlyphs___CIIFFIPaint},
-    {"native_drawTextWithGlyphs","(ILjava/lang/String;IIFFII)V",
-        (void*) SkCanvasGlue::drawTextWithGlyphs__StringIIFFIPaint},
-    {"native_drawGlyphs","(I[CIIFFII)V",
-        (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
     {"native_drawTextRun","(I[CIIIIFFII)V",
         (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
     {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index d30e0ae..b0c2f2c 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -867,10 +867,8 @@
 
 const char* const kActivityThreadPathName = "android/app/ActivityThread";
 
-int register_android_app_ActivityThread(JNIEnv* env)
-{
-    return AndroidRuntime::registerNativeMethods(
-            env, kActivityThreadPathName,
+int register_android_app_ActivityThread(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kActivityThreadPathName,
             gActivityThreadMethods, NELEM(gActivityThreadMethods));
 }
 
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index b046b23..9484c6b 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -19,11 +19,48 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
 #include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
 
 namespace android {
 
 // ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+static struct {
+    jmethodID set;
+    jfieldID left;
+    jfieldID top;
+    jfieldID right;
+    jfieldID bottom;
+} gRectClassInfo;
+
+static struct {
+    jfieldID nativeCanvas;
+    jfieldID surfaceFormat;
+} gCanvasClassInfo;
+
+static struct {
+    jfieldID nativeWindow;
+} gTextureViewClassInfo;
+
+#define GET_INT(object, field) \
+    env->GetIntField(object, field)
+
+#define SET_INT(object, field, value) \
+    env->SetIntField(object, field, value)
+
+#define INVOKEV(object, method, ...) \
+    env->CallVoidMethod(object, method, __VA_ARGS__)
+
+// ----------------------------------------------------------------------------
 // Native layer
 // ----------------------------------------------------------------------------
 
@@ -34,6 +71,118 @@
     surfaceTexture->setDefaultBufferSize(width, height);
 }
 
+static inline SkBitmap::Config convertPixelFormat(int32_t format) {
+    switch (format) {
+        case WINDOW_FORMAT_RGBA_8888:
+            return SkBitmap::kARGB_8888_Config;
+        case WINDOW_FORMAT_RGBX_8888:
+            return SkBitmap::kARGB_8888_Config;
+        case WINDOW_FORMAT_RGB_565:
+            return SkBitmap::kRGB_565_Config;
+        default:
+            return SkBitmap::kNo_Config;
+    }
+}
+
+/**
+ * This is a private API, and this implementation is also provided in the NDK.
+ * However, the NDK links against android_runtime, which means that using the
+ * NDK implementation would create a circular dependency between the libraries.
+ */
+static int32_t native_window_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+        Rect* inOutDirtyBounds) {
+    return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
+}
+
+static int32_t native_window_unlockAndPost(ANativeWindow* window) {
+    return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
+}
+
+static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView,
+        jobject surface) {
+
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+    sp<ANativeWindow> window = new SurfaceTextureClient(surfaceTexture);
+
+    window->incStrong(0);
+    SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
+}
+
+static void android_view_TextureView_destroyNativeWindow(JNIEnv* env, jobject textureView) {
+
+    ANativeWindow* nativeWindow = (ANativeWindow*)
+            GET_INT(textureView, gTextureViewClassInfo.nativeWindow);
+
+    if (nativeWindow) {
+        sp<ANativeWindow> window(nativeWindow);
+            window->decStrong(0);
+        SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0);
+    }
+}
+
+static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
+        jint nativeWindow, jobject canvas, jobject dirtyRect) {
+
+    if (!nativeWindow) {
+        return;
+    }
+
+    ANativeWindow_Buffer buffer;
+
+    Rect rect;
+    if (dirtyRect) {
+        rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
+        rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
+        rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
+        rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
+    } else {
+        rect.set(Rect(0x3FFF, 0x3FFF));
+    }
+
+    sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
+    native_window_lock(window.get(), &buffer, &rect);
+
+    ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format);
+
+    SkBitmap bitmap;
+    bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount);
+
+    if (buffer.format == WINDOW_FORMAT_RGBX_8888) {
+        bitmap.setIsOpaque(true);
+    }
+
+    if (buffer.width > 0 && buffer.height > 0) {
+        bitmap.setPixels(buffer.bits);
+    } else {
+        bitmap.setPixels(NULL);
+    }
+
+    SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format);
+    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+    nativeCanvas->setBitmapDevice(bitmap);
+
+    SkRect clipRect;
+    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
+    nativeCanvas->clipRect(clipRect);
+
+    if (dirtyRect) {
+        INVOKEV(dirtyRect, gRectClassInfo.set,
+                int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
+    }
+}
+
+static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
+        jint nativeWindow, jobject canvas) {
+
+    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+    nativeCanvas->setBitmapDevice(SkBitmap());
+
+    if (nativeWindow) {
+        sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
+        native_window_unlockAndPost(window.get());
+    }
+}
+
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -42,10 +191,47 @@
 
 static JNINativeMethod gMethods[] = {
     {   "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V",
-            (void*) android_view_TextureView_setDefaultBufferSize }
+            (void*) android_view_TextureView_setDefaultBufferSize },
+
+    {   "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
+            (void*) android_view_TextureView_createNativeWindow },
+    {   "nDestroyNativeWindow", "()V",
+            (void*) android_view_TextureView_destroyNativeWindow },
+
+    {   "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V",
+            (void*) android_view_TextureView_lockCanvas },
+    {   "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
+            (void*) android_view_TextureView_unlockCanvasAndPost },
 };
 
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(!var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(!var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(!var, "Unable to find field" fieldName);
+
 int register_android_view_TextureView(JNIEnv* env) {
+    jclass clazz;
+    FIND_CLASS(clazz, "android/graphics/Rect");
+    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
+    GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
+    GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
+    GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
+    GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
+
+    FIND_CLASS(clazz, "android/graphics/Canvas");
+    GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I");
+    GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I");
+
+    FIND_CLASS(clazz, "android/view/TextureView");
+    GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I");
+
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9613712..d0361ca 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2302,6 +2302,8 @@
         <!-- Flag whether the accessibility service wants to be able to retrieve the
              active window content. This setting cannot be changed at runtime. -->
         <attr name="canRetrieveWindowContent" format="boolean" />
+        <!-- Short description of the accessibility serivce purpose or behavior.-->
+        <attr name="description" />
     </declare-styleable>
 
     <!-- =============================== -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index abc56ec..73f636f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -138,4 +138,7 @@
     <!-- Minimum popup width for selecting an activity in ActivityChooserDialog/ActivityChooserView. -->
     <dimen name="activity_chooser_popup_min_width">200dip</dimen>
 
+    <!-- The default gap between components in a layout. -->
+    <dimen name="default_gap">16dip</dimen>
+
 </resources>
diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java
index b5c2c27..440aeb5 100644
--- a/core/tests/coretests/src/android/util/JsonReaderTest.java
+++ b/core/tests/coretests/src/android/util/JsonReaderTest.java
@@ -856,4 +856,33 @@
         } catch (IOException expected) {
         }
     }
+
+    public void testFailWithPosition() throws IOException {
+        testFailWithPosition("Expected literal value at line 6 column   3",
+                "[\n\n\n\n\n0,}]");
+    }
+
+    public void testFailWithPositionGreaterThanBufferSize() throws IOException {
+        String spaces = repeat(' ', 8192);
+        testFailWithPosition("Expected literal value at line 6 column 3",
+                "[\n\n" + spaces + "\n\n\n0,}]");
+    }
+
+    private void testFailWithPosition(String message, String json) throws IOException {
+        JsonReader reader = new JsonReader(new StringReader(json));
+        reader.beginArray();
+        reader.nextInt();
+        try {
+            reader.peek();
+            fail();
+        } catch (IOException expected) {
+            assertEquals(message, expected.getMessage());
+        }
+    }
+
+    private String repeat(char c, int count) {
+        char[] array = new char[count];
+        Arrays.fill(array, c);
+        return new String(array);
+    }
 }
diff --git a/core/tests/coretests/src/android/util/JsonWriterTest.java b/core/tests/coretests/src/android/util/JsonWriterTest.java
index b29e2fd..1239a3c 100644
--- a/core/tests/coretests/src/android/util/JsonWriterTest.java
+++ b/core/tests/coretests/src/android/util/JsonWriterTest.java
@@ -289,6 +289,15 @@
                 + "\"\\u0019\"]", stringWriter.toString());
     }
 
+    public void testUnicodeLineBreaksEscaped() throws IOException {
+        StringWriter stringWriter = new StringWriter();
+        JsonWriter jsonWriter = new JsonWriter(stringWriter);
+        jsonWriter.beginArray();
+        jsonWriter.value("\u2028 \u2029");
+        jsonWriter.endArray();
+        assertEquals("[\"\\u2028 \\u2029\"]", stringWriter.toString());
+    }
+
     public void testEmptyArray() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5b50f8f..35ed4d2 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1414,77 +1414,13 @@
         } else {
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
-            native_drawText(mNativeCanvas, buf, 0, end - start, x, y, 
+            native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
                     paint.mBidiFlags, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
 
     /**
-     * Draw the text, with origin at (x,y), using the specified paint. The
-     * origin is interpreted based on the Align setting in the paint.
-     *
-     * @param text  The text to be drawn
-     * @param x     The x-coordinate of the origin of the text being drawn
-     * @param y     The y-coordinate of the origin of the text being drawn
-     * @param paint The paint used for the text (e.g. color, size, style)
-     *
-     * @hide
-     *
-     * Used only for BiDi / RTL Tests
-     */
-    public void drawTextWithGlyphs(char[] text, int index, int count, float x, float y,
-                         Paint paint) {
-        if ((index | count | (index + count) |
-            (text.length - index - count)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        native_drawTextWithGlyphs(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
-    }
-
-    /**
-     * Draw the text, with origin at (x,y), using the specified paint. The
-     * origin is interpreted based on the Align setting in the paint.
-     *
-     * @param text  The text to be drawn
-     * @param x     The x-coordinate of the origin of the text being drawn
-     * @param y     The y-coordinate of the origin of the text being drawn
-     * @param paint The paint used for the text (e.g. color, size, style)
-     *
-     * @hide
-     *
-     * Used only for BiDi / RTL Tests
-     */
-    public void drawTextWithGlyphs(String text, float x, float y, Paint paint) {
-        native_drawTextWithGlyphs(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
-                paint.mNativePaint);
-    }
-
-    /**
-     * Draw the glyphs, with origin at (x,y), using the specified paint. The
-     * origin is interpreted based on the Align setting in the paint.
-     *
-     * @param glyphs The glyphs to be drawn
-     * @param x      The x-coordinate of the origin of the text being drawn
-     * @param y      The y-coordinate of the origin of the text being drawn
-     * @param paint  The paint used for the text (e.g. color, size, style)
-     *
-     * @hide
-     *
-     * Used only for BiDi / RTL Tests
-     */
-    public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
-                         Paint paint) {
-        if ((index | count | (index + count) |
-            (glyphs.length - index - count)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
-    }
-
-    /**
      * Render a run of all LTR or all RTL text, with shaping. This does not run
      * bidi on the provided text, but renders it as a uniform right-to-left or
      * left-to-right run, as indicated by dir. Alignment of the text is as
@@ -1813,16 +1749,6 @@
                                                int start, int end, float x,
                                                float y, int flags, int paint);
 
-    private static native void native_drawTextWithGlyphs(int nativeCanvas, char[] text,
-                                               int index, int count, float x,
-                                               float y, int flags, int paint);
-    private static native void native_drawTextWithGlyphs(int nativeCanvas, String text,
-                                               int start, int end, float x,
-                                               float y, int flags, int paint);
-    private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs,
-                                               int index, int count, float x,
-                                               float y, int flags, int paint);
-
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
             float x, float y, int flags, int paint);
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 5ec469e..cfe2aa1 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -21,6 +21,7 @@
 #include <gui/SurfaceTexture.h>
 
 #include <ui/egl/android_natives.h>
+#include <ui/Region.h>
 
 #include <utils/RefBase.h>
 #include <utils/threads.h>
@@ -37,29 +38,24 @@
 
     sp<ISurfaceTexture> getISurfaceTexture() const;
 
-private:
-    friend class Surface;
+protected:
+    SurfaceTextureClient();
+    void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
 
+private:
     // can't be copied
     SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
     SurfaceTextureClient(const SurfaceTextureClient& rhs);
+    void init();
 
     // ANativeWindow hooks
-    static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
-    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int perform(ANativeWindow* window, int operation, ...);
-    static int query(const ANativeWindow* window, int what, int* value);
-    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int setSwapInterval(ANativeWindow* window, int interval);
-
-    int cancelBuffer(ANativeWindowBuffer* buffer);
-    int dequeueBuffer(ANativeWindowBuffer** buffer);
-    int lockBuffer(ANativeWindowBuffer* buffer);
-    int perform(int operation, va_list args);
-    int query(int what, int* value) const;
-    int queueBuffer(ANativeWindowBuffer* buffer);
-    int setSwapInterval(int interval);
+    static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+    static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_perform(ANativeWindow* window, int operation, ...);
+    static int hook_query(const ANativeWindow* window, int what, int* value);
+    static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_setSwapInterval(ANativeWindow* window, int interval);
 
     int dispatchConnect(va_list args);
     int dispatchDisconnect(va_list args);
@@ -71,26 +67,38 @@
     int dispatchSetBuffersTimestamp(va_list args);
     int dispatchSetCrop(va_list args);
     int dispatchSetUsage(va_list args);
+    int dispatchLock(va_list args);
+    int dispatchUnlockAndPost(va_list args);
 
-    int connect(int api);
-    int disconnect(int api);
-    int setBufferCount(int bufferCount);
-    int setBuffersDimensions(int w, int h);
-    int setBuffersFormat(int format);
-    int setBuffersTransform(int transform);
-    int setBuffersTimestamp(int64_t timestamp);
-    int setCrop(Rect const* rect);
-    int setUsage(uint32_t reqUsage);
+protected:
+    virtual int cancelBuffer(ANativeWindowBuffer* buffer);
+    virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
+    virtual int lockBuffer(ANativeWindowBuffer* buffer);
+    virtual int perform(int operation, va_list args);
+    virtual int query(int what, int* value) const;
+    virtual int queueBuffer(ANativeWindowBuffer* buffer);
+    virtual int setSwapInterval(int interval);
 
-    void freeAllBuffers();
-    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
-
-    int getConnectedApi() const;
+    virtual int connect(int api);
+    virtual int disconnect(int api);
+    virtual int setBufferCount(int bufferCount);
+    virtual int setBuffersDimensions(int w, int h);
+    virtual int setBuffersFormat(int format);
+    virtual int setBuffersTransform(int transform);
+    virtual int setBuffersTimestamp(int64_t timestamp);
+    virtual int setCrop(Rect const* rect);
+    virtual int setUsage(uint32_t reqUsage);
+    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+    virtual int unlockAndPost();
 
     enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
     enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
 
+private:
+    void freeAllBuffers();
+    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
     // mSurfaceTexture is the interface to the surface texture server. All
     // operations on the surface texture client ultimately translate into
     // interactions with the server using this interface.
@@ -145,6 +153,12 @@
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
     mutable Mutex mMutex;
+
+    // must be used from the lock/unlock thread
+    sp<GraphicBuffer>           mLockedBuffer;
+    sp<GraphicBuffer>           mPostedBuffer;
+    mutable Region              mOldDirtyRegion;
+    bool                        mConnectedToCpu;
 };
 
 }; // namespace android
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index ea5a9d3..1136f6c 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -25,6 +25,8 @@
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 
+class ANativeWindow;
+
 namespace android {
 
 class Surface;
@@ -196,6 +198,8 @@
             status_t        prepareAsync_l();
             status_t        getDuration_l(int *msec);
             status_t        setDataSource(const sp<IMediaPlayer>& player);
+            void            disconnectNativeWindow();
+            status_t        reset_l();
 
     sp<IMediaPlayer>            mPlayer;
     thread_id_t                 mLockThreadId;
@@ -218,6 +222,8 @@
     int                         mVideoHeight;
     int                         mAudioSessionId;
     float                       mSendLevel;
+    sp<ANativeWindow>           mConnectedWindow;
+    sp<IBinder>                 mConnectedWindowBinder;
 };
 
 }; // namespace android
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index dc2a845..c2a494d 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -28,6 +28,8 @@
 #include <ui/Region.h>
 #include <ui/egl/android_natives.h>
 
+#include <gui/SurfaceTextureClient.h>
+
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceComposerClient.h>
 
@@ -37,14 +39,9 @@
 
 // ---------------------------------------------------------------------------
 
-class GraphicBuffer;
-class GraphicBufferMapper;
-class IOMX;
 class ISurfaceTexture;
-class Rect;
 class Surface;
 class SurfaceComposerClient;
-class SurfaceTextureClient;
 
 // ---------------------------------------------------------------------------
 
@@ -129,8 +126,7 @@
     
 // ---------------------------------------------------------------------------
 
-class Surface 
-    : public EGLNativeBase<ANativeWindow, Surface, RefBase>
+class Surface : public SurfaceTextureClient
 {
 public:
     struct SurfaceInfo {
@@ -158,32 +154,14 @@
     sp<ISurfaceTexture> getSurfaceTexture();
 
     // the lock/unlock APIs must be used from the same thread
-    status_t    lock(SurfaceInfo* info, bool blocking = true);
-    status_t    lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+    status_t    lock(SurfaceInfo* info, Region* dirty = NULL);
     status_t    unlockAndPost();
 
     sp<IBinder> asBinder() const;
 
 private:
-    /*
-     * Android frameworks friends
-     * (eventually this should go away and be replaced by proper APIs)
-     */
-    // camera and camcorder need access to the ISurface binder interface for preview
-    friend class CameraService;
-    friend class MediaRecorder;
-    // MediaPlayer needs access to ISurface for display
-    friend class MediaPlayer;
-    friend class IOMX;
-    friend class SoftwareRenderer;
     // this is just to be able to write some unit tests
     friend class Test;
-    // videoEditor preview classes
-    friend class VideoEditorPreviewController;
-    friend class PreviewRenderer;
-
-private:
-    friend class SurfaceComposerClient;
     friend class SurfaceControl;
 
     // can't be copied
@@ -194,62 +172,27 @@
     Surface(const Parcel& data, const sp<IBinder>& ref);
     ~Surface();
 
-
-    /*
-     *  ANativeWindow hooks
-     */
-    static int setSwapInterval(ANativeWindow* window, int interval);
-    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
-    static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int query(const ANativeWindow* window, int what, int* value);
-    static int perform(ANativeWindow* window, int operation, ...);
-
-    int setSwapInterval(int interval);
-    int dequeueBuffer(ANativeWindowBuffer** buffer);
-    int lockBuffer(ANativeWindowBuffer* buffer);
-    int queueBuffer(ANativeWindowBuffer* buffer);
-    int cancelBuffer(ANativeWindowBuffer* buffer);
-    int query(int what, int* value) const;
-    int perform(int operation, va_list args);
-
     /*
      *  private stuff...
      */
     void init();
     status_t validate(bool inCancelBuffer = false) const;
 
-    int getConnectedApi() const;
-    
     static void cleanCachedSurfacesLocked();
 
+    virtual int query(int what, int* value) const;
+
     // constants
     status_t                    mInitCheck;
     sp<ISurface>                mSurface;
-    sp<SurfaceTextureClient>    mSurfaceTextureClient;
     uint32_t                    mIdentity;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
-    
-    // protected by mSurfaceLock. These are also used from lock/unlock
-    // but in that case, they must be called form the same thread.
-    mutable Region              mDirtyRegion;
-
-    // must be used from the lock/unlock thread
-    sp<GraphicBuffer>           mLockedBuffer;
-    sp<GraphicBuffer>           mPostedBuffer;
-    mutable Region              mOldDirtyRegion;
-    bool                        mReserved;
 
     // query() must be called from dequeueBuffer() thread
     uint32_t                    mWidth;
     uint32_t                    mHeight;
 
-    // Inherently thread-safe
-    mutable Mutex               mSurfaceLock;
-    mutable Mutex               mApiLock;
-
     // A cache of Surface objects that have been deserialized into this process.
     static Mutex sCachedSurfacesLock;
     static DefaultKeyedVector<wp<IBinder>, wp<Surface> > sCachedSurfaces;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9185e1e..dabe643f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -46,59 +46,6 @@
 
 namespace android {
 
-// ----------------------------------------------------------------------
-
-static status_t copyBlt(
-        const sp<GraphicBuffer>& dst, 
-        const sp<GraphicBuffer>& src, 
-        const Region& reg)
-{
-    // src and dst with, height and format must be identical. no verification
-    // is done here.
-    status_t err;
-    uint8_t const * src_bits = NULL;
-    err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
-    LOGE_IF(err, "error locking src buffer %s", strerror(-err));
-
-    uint8_t* dst_bits = NULL;
-    err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
-    LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
-
-    Region::const_iterator head(reg.begin());
-    Region::const_iterator tail(reg.end());
-    if (head != tail && src_bits && dst_bits) {
-        const size_t bpp = bytesPerPixel(src->format);
-        const size_t dbpr = dst->stride * bpp;
-        const size_t sbpr = src->stride * bpp;
-
-        while (head != tail) {
-            const Rect& r(*head++);
-            ssize_t h = r.height();
-            if (h <= 0) continue;
-            size_t size = r.width() * bpp;
-            uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
-            uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
-            if (dbpr==sbpr && size==sbpr) {
-                size *= h;
-                h = 1;
-            }
-            do {
-                memcpy(d, s, size);
-                d += dbpr;
-                s += sbpr;
-            } while (--h > 0);
-        }
-    }
-    
-    if (src_bits)
-        src->unlock();
-    
-    if (dst_bits)
-        dst->unlock();
-    
-    return err;
-}
-
 // ============================================================================
 //  SurfaceControl
 // ============================================================================
@@ -277,7 +224,8 @@
 // ---------------------------------------------------------------------------
 
 Surface::Surface(const sp<SurfaceControl>& surface)
-    : mInitCheck(NO_INIT),
+    : SurfaceTextureClient(),
+      mInitCheck(NO_INIT),
       mSurface(surface->mSurface),
       mIdentity(surface->mIdentity),
       mFormat(surface->mFormat), mFlags(surface->mFlags),
@@ -287,7 +235,8 @@
 }
 
 Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
-    : mInitCheck(NO_INIT)
+    : SurfaceTextureClient(),
+      mInitCheck(NO_INIT)
 {
     mSurface    = interface_cast<ISurface>(ref);
     mIdentity   = parcel.readInt32();
@@ -363,36 +312,21 @@
 
 void Surface::init()
 {
-    ANativeWindow::setSwapInterval  = setSwapInterval;
-    ANativeWindow::dequeueBuffer    = dequeueBuffer;
-    ANativeWindow::cancelBuffer     = cancelBuffer;
-    ANativeWindow::lockBuffer       = lockBuffer;
-    ANativeWindow::queueBuffer      = queueBuffer;
-    ANativeWindow::query            = query;
-    ANativeWindow::perform          = perform;
-
     if (mSurface != NULL) {
         sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
         LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
         if (surfaceTexture != NULL) {
-            mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
-            mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+            setISurfaceTexture(surfaceTexture);
+            setUsage(GraphicBuffer::USAGE_HW_RENDER);
         }
 
         DisplayInfo dinfo;
         SurfaceComposerClient::getDisplayInfo(0, &dinfo);
         const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
         const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-
-        const_cast<int&>(ANativeWindow::minSwapInterval) =
-                mSurfaceTextureClient->minSwapInterval;
-
-        const_cast<int&>(ANativeWindow::maxSwapInterval) =
-                mSurfaceTextureClient->maxSwapInterval;
-
         const_cast<uint32_t&>(ANativeWindow::flags) = 0;
 
-        if (mSurfaceTextureClient != 0) {
+        if (surfaceTexture != NULL) {
             mInitCheck = NO_ERROR;
         }
     }
@@ -402,7 +336,6 @@
 {
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
-    mSurfaceTextureClient.clear();
     mSurface.clear();
     IPCThreadState::self()->flushCommands();
 }
@@ -431,77 +364,6 @@
 
 // ----------------------------------------------------------------------------
 
-int Surface::setSwapInterval(ANativeWindow* window, int interval) {
-    Surface* self = getSelf(window);
-    return self->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindow* window, 
-        ANativeWindowBuffer** buffer) {
-    Surface* self = getSelf(window);
-    return self->dequeueBuffer(buffer);
-}
-
-int Surface::cancelBuffer(ANativeWindow* window,
-        ANativeWindowBuffer* buffer) {
-    Surface* self = getSelf(window);
-    return self->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindow* window, 
-        ANativeWindowBuffer* buffer) {
-    Surface* self = getSelf(window);
-    return self->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindow* window, 
-        ANativeWindowBuffer* buffer) {
-    Surface* self = getSelf(window);
-    return self->queueBuffer(buffer);
-}
-
-int Surface::query(const ANativeWindow* window,
-        int what, int* value) {
-    const Surface* self = getSelf(window);
-    return self->query(what, value);
-}
-
-int Surface::perform(ANativeWindow* window, 
-        int operation, ...) {
-    va_list args;
-    va_start(args, operation);
-    Surface* self = getSelf(window);
-    int res = self->perform(operation, args);
-    va_end(args);
-    return res;
-}
-
-// ----------------------------------------------------------------------------
-
-int Surface::setSwapInterval(int interval) {
-    return mSurfaceTextureClient->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
-    status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
-    if (err == NO_ERROR) {
-        mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
-    }
-    return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
-    return mSurfaceTextureClient->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
-    return mSurfaceTextureClient->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
-    return mSurfaceTextureClient->queueBuffer(buffer);
-}
-
 int Surface::query(int what, int* value) const {
     switch (what) {
     case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
@@ -509,141 +371,39 @@
         *value = 1;
         return NO_ERROR;
     case NATIVE_WINDOW_CONCRETE_TYPE:
-        // TODO: this is not needed anymore
         *value = NATIVE_WINDOW_SURFACE;
         return NO_ERROR;
     }
-    return mSurfaceTextureClient->query(what, value);
-}
-
-int Surface::perform(int operation, va_list args) {
-    return mSurfaceTextureClient->perform(operation, args);
+    return SurfaceTextureClient::query(what, value);
 }
 
 // ----------------------------------------------------------------------------
 
-int Surface::getConnectedApi() const {
-    return mSurfaceTextureClient->getConnectedApi();
-}
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
+    ANativeWindow_Buffer outBuffer;
 
-// ----------------------------------------------------------------------------
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
-    return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) 
-{
-    if (getConnectedApi()) {
-        LOGE("Surface::lock(%p) failed. Already connected to another API",
-                (ANativeWindow*)this);
-        CallStack stack;
-        stack.update();
-        stack.dump("");
-        return INVALID_OPERATION;
+    ARect temp;
+    ARect* inOutDirtyBounds = NULL;
+    if (dirtyIn) {
+        temp = dirtyIn->getBounds();
+        inOutDirtyBounds = &temp;
     }
 
-    if (mApiLock.tryLock() != NO_ERROR) {
-        LOGE("calling Surface::lock from different threads!");
-        CallStack stack;
-        stack.update();
-        stack.dump("");
-        return WOULD_BLOCK;
-    }
+    status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
 
-    /* Here we're holding mApiLock */
-    
-    if (mLockedBuffer != 0) {
-        LOGE("Surface::lock failed, already locked");
-        mApiLock.unlock();
-        return INVALID_OPERATION;
-    }
-
-    // we're intending to do software rendering from this point
-    mSurfaceTextureClient->setUsage(
-            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
-    ANativeWindowBuffer* out;
-    status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
-    LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
     if (err == NO_ERROR) {
-        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
-        err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
-        LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
-                backBuffer->handle, strerror(-err));
-        if (err == NO_ERROR) {
-            const Rect bounds(backBuffer->width, backBuffer->height);
-            const Region boundsRegion(bounds);
-            Region scratch(boundsRegion);
-            Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
-            newDirtyRegion &= boundsRegion;
-
-            // figure out if we can copy the frontbuffer back
-            const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
-            const bool canCopyBack = (frontBuffer != 0 &&
-                    backBuffer->width  == frontBuffer->width &&
-                    backBuffer->height == frontBuffer->height &&
-                    backBuffer->format == frontBuffer->format &&
-                    !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
-
-            // the dirty region we report to surfaceflinger is the one
-            // given by the user (as opposed to the one *we* return to the
-            // user).
-            mDirtyRegion = newDirtyRegion;
-
-            if (canCopyBack) {
-                // copy the area that is invalid and not repainted this round
-                const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
-                if (!copyback.isEmpty())
-                    copyBlt(backBuffer, frontBuffer, copyback);
-            } else {
-                // if we can't copy-back anything, modify the user's dirty
-                // region to make sure they redraw the whole buffer
-                newDirtyRegion = boundsRegion;
-            }
-
-            // keep track of the are of the buffer that is "clean"
-            // (ie: that will be redrawn)
-            mOldDirtyRegion = newDirtyRegion;
-
-            void* vaddr;
-            status_t res = backBuffer->lock(
-                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-                    newDirtyRegion.bounds(), &vaddr);
-            
-            LOGW_IF(res, "failed locking buffer (handle = %p)", 
-                    backBuffer->handle);
-
-            mLockedBuffer = backBuffer;
-            other->w      = backBuffer->width;
-            other->h      = backBuffer->height;
-            other->s      = backBuffer->stride;
-            other->usage  = backBuffer->usage;
-            other->format = backBuffer->format;
-            other->bits   = vaddr;
-        }
+        other->w = uint32_t(outBuffer.width);
+        other->h = uint32_t(outBuffer.height);
+        other->s = uint32_t(outBuffer.stride);
+        other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+        other->format = uint32_t(outBuffer.format);
+        other->bits = outBuffer.bits;
     }
-    mApiLock.unlock();
     return err;
 }
-    
-status_t Surface::unlockAndPost() 
-{
-    if (mLockedBuffer == 0) {
-        LOGE("Surface::unlockAndPost failed, no locked buffer");
-        return INVALID_OPERATION;
-    }
 
-    status_t err = mLockedBuffer->unlock();
-    LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
-    
-    err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
-    LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
-            mLockedBuffer->handle, strerror(-err));
-
-    mPostedBuffer = mLockedBuffer;
-    mLockedBuffer = 0;
-    return err;
+status_t Surface::unlockAndPost() {
+    return SurfaceTextureClient::unlockAndPost();
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1410481..a12d40a 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -495,7 +495,7 @@
 }
 
 status_t SurfaceTexture::connect(int api) {
-    LOGV("SurfaceTexture::connect");
+    LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
     Mutex::Autolock lock(mMutex);
     int err = NO_ERROR;
     switch (api) {
@@ -504,6 +504,8 @@
         case NATIVE_WINDOW_API_MEDIA:
         case NATIVE_WINDOW_API_CAMERA:
             if (mConnectedApi != NO_CONNECTED_API) {
+                LOGE("connect: already connected (cur=%d, req=%d)",
+                        mConnectedApi, api);
                 err = -EINVAL;
             } else {
                 mConnectedApi = api;
@@ -517,7 +519,7 @@
 }
 
 status_t SurfaceTexture::disconnect(int api) {
-    LOGV("SurfaceTexture::disconnect");
+    LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
     Mutex::Autolock lock(mMutex);
     int err = NO_ERROR;
     switch (api) {
@@ -528,6 +530,8 @@
             if (mConnectedApi == api) {
                 mConnectedApi = NO_CONNECTED_API;
             } else {
+                LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                        mConnectedApi, api);
                 err = -EINVAL;
             }
             break;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f39cabf..d5b7c89 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -24,24 +24,45 @@
 namespace android {
 
 SurfaceTextureClient::SurfaceTextureClient(
-        const sp<ISurfaceTexture>& surfaceTexture):
-        mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
-        mReqHeight(0), mReqFormat(0), mReqUsage(0),
-        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
-        mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
-        mMutex() {
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    SurfaceTextureClient::init();
+    SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
+}
+
+SurfaceTextureClient::SurfaceTextureClient() {
+    SurfaceTextureClient::init();
+}
+
+void SurfaceTextureClient::init() {
     // Initialize the ANativeWindow function pointers.
-    ANativeWindow::setSwapInterval  = setSwapInterval;
-    ANativeWindow::dequeueBuffer    = dequeueBuffer;
-    ANativeWindow::cancelBuffer     = cancelBuffer;
-    ANativeWindow::lockBuffer       = lockBuffer;
-    ANativeWindow::queueBuffer      = queueBuffer;
-    ANativeWindow::query            = query;
-    ANativeWindow::perform          = perform;
+    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
+    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
+    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
+    ANativeWindow::lockBuffer       = hook_lockBuffer;
+    ANativeWindow::queueBuffer      = hook_queueBuffer;
+    ANativeWindow::query            = hook_query;
+    ANativeWindow::perform          = hook_perform;
 
     const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
     const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
 
+    mReqWidth = 0;
+    mReqHeight = 0;
+    mReqFormat = 0;
+    mReqUsage = 0;
+    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    mQueryWidth = 0;
+    mQueryHeight = 0;
+    mQueryFormat = 0;
+    mConnectedToCpu = false;
+}
+
+void SurfaceTextureClient::setISurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    mSurfaceTexture = surfaceTexture;
+
     // Get a reference to the allocator.
     mAllocator = mSurfaceTexture->getAllocator();
 }
@@ -50,42 +71,42 @@
     return mSurfaceTexture;
 }
 
-int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
     SurfaceTextureClient* c = getSelf(window);
     return c->setSwapInterval(interval);
 }
 
-int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
         ANativeWindowBuffer** buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->dequeueBuffer(buffer);
 }
 
-int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
         ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->cancelBuffer(buffer);
 }
 
-int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
         ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->lockBuffer(buffer);
 }
 
-int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
         ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->queueBuffer(buffer);
 }
 
-int SurfaceTextureClient::query(const ANativeWindow* window,
+int SurfaceTextureClient::hook_query(const ANativeWindow* window,
                                 int what, int* value) {
     const SurfaceTextureClient* c = getSelf(window);
     return c->query(what, value);
 }
 
-int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
     va_list args;
     va_start(args, operation);
     SurfaceTextureClient* c = getSelf(window);
@@ -219,7 +240,6 @@
         *value = 0;
         return NO_ERROR;
     case NATIVE_WINDOW_CONCRETE_TYPE:
-        // TODO: this is not needed anymore
         *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
         return NO_ERROR;
     }
@@ -260,6 +280,12 @@
     case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
         res = dispatchSetBuffersFormat(args);
         break;
+    case NATIVE_WINDOW_LOCK:
+        res = dispatchLock(args);
+        break;
+    case NATIVE_WINDOW_UNLOCK_AND_POST:
+        res = dispatchUnlockAndPost(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -324,28 +350,37 @@
     return setBuffersTimestamp(timestamp);
 }
 
+int SurfaceTextureClient::dispatchLock(va_list args) {
+    ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+    ARect* inOutDirtyBounds = va_arg(args, ARect*);
+    return lock(outBuffer, inOutDirtyBounds);
+}
+
+int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
+    return unlockAndPost();
+}
+
+
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
     Mutex::Autolock lock(mMutex);
-    return mSurfaceTexture->connect(api);
+    int err = mSurfaceTexture->connect(api);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = true;
+    }
+    return err;
 }
 
 int SurfaceTextureClient::disconnect(int api) {
     LOGV("SurfaceTextureClient::disconnect");
     Mutex::Autolock lock(mMutex);
-    return mSurfaceTexture->disconnect(api);
+    int err = mSurfaceTexture->disconnect(api);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = false;
+    }
+    return err;
 }
 
-int SurfaceTextureClient::getConnectedApi() const
-{
-    // XXX: This method will be going away shortly, and is currently bogus.  It
-    // always returns "nothing is connected".  It will go away once Surface gets
-    // updated to actually connect as the 'CPU' API when locking a buffer.
-    Mutex::Autolock lock(mMutex);
-    return 0;
-}
-
-
 int SurfaceTextureClient::setUsage(uint32_t reqUsage)
 {
     LOGV("SurfaceTextureClient::setUsage");
@@ -443,4 +478,160 @@
     }
 }
 
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+        const sp<GraphicBuffer>& dst,
+        const sp<GraphicBuffer>& src,
+        const Region& reg)
+{
+    // src and dst with, height and format must be identical. no verification
+    // is done here.
+    status_t err;
+    uint8_t const * src_bits = NULL;
+    err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+    LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+    uint8_t* dst_bits = NULL;
+    err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+    LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+    Region::const_iterator head(reg.begin());
+    Region::const_iterator tail(reg.end());
+    if (head != tail && src_bits && dst_bits) {
+        const size_t bpp = bytesPerPixel(src->format);
+        const size_t dbpr = dst->stride * bpp;
+        const size_t sbpr = src->stride * bpp;
+
+        while (head != tail) {
+            const Rect& r(*head++);
+            ssize_t h = r.height();
+            if (h <= 0) continue;
+            size_t size = r.width() * bpp;
+            uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+            uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+            if (dbpr==sbpr && size==sbpr) {
+                size *= h;
+                h = 1;
+            }
+            do {
+                memcpy(d, s, size);
+                d += dbpr;
+                s += sbpr;
+            } while (--h > 0);
+        }
+    }
+
+    if (src_bits)
+        src->unlock();
+
+    if (dst_bits)
+        dst->unlock();
+
+    return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceTextureClient::lock(
+        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+    if (mLockedBuffer != 0) {
+        LOGE("Surface::lock failed, already locked");
+        return INVALID_OPERATION;
+    }
+
+    if (!mConnectedToCpu) {
+        int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
+        if (err) {
+            return err;
+        }
+        // we're intending to do software rendering from this point
+        setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+    }
+
+    ANativeWindowBuffer* out;
+    status_t err = dequeueBuffer(&out);
+    LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+    if (err == NO_ERROR) {
+        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+        err = lockBuffer(backBuffer.get());
+        LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+                backBuffer->handle, strerror(-err));
+        if (err == NO_ERROR) {
+            const Rect bounds(backBuffer->width, backBuffer->height);
+
+            Region newDirtyRegion;
+            if (inOutDirtyBounds) {
+                newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+                newDirtyRegion.andSelf(bounds);
+            } else {
+                newDirtyRegion.set(bounds);
+            }
+
+            // figure out if we can copy the frontbuffer back
+            const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+            const bool canCopyBack = (frontBuffer != 0 &&
+                    backBuffer->width  == frontBuffer->width &&
+                    backBuffer->height == frontBuffer->height &&
+                    backBuffer->format == frontBuffer->format);
+
+            if (canCopyBack) {
+                // copy the area that is invalid and not repainted this round
+                const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+                if (!copyback.isEmpty())
+                    copyBlt(backBuffer, frontBuffer, copyback);
+            } else {
+                // if we can't copy-back anything, modify the user's dirty
+                // region to make sure they redraw the whole buffer
+                newDirtyRegion.set(bounds);
+            }
+
+            // keep track of the are of the buffer that is "clean"
+            // (ie: that will be redrawn)
+            mOldDirtyRegion = newDirtyRegion;
+
+            if (inOutDirtyBounds) {
+                *inOutDirtyBounds = newDirtyRegion.getBounds();
+            }
+
+            void* vaddr;
+            status_t res = backBuffer->lock(
+                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                    newDirtyRegion.bounds(), &vaddr);
+
+            LOGW_IF(res, "failed locking buffer (handle = %p)",
+                    backBuffer->handle);
+
+            mLockedBuffer = backBuffer;
+            outBuffer->width  = backBuffer->width;
+            outBuffer->height = backBuffer->height;
+            outBuffer->stride = backBuffer->stride;
+            outBuffer->format = backBuffer->format;
+            outBuffer->bits   = vaddr;
+        }
+    }
+    return err;
+}
+
+status_t SurfaceTextureClient::unlockAndPost()
+{
+    if (mLockedBuffer == 0) {
+        LOGE("Surface::unlockAndPost failed, no locked buffer");
+        return INVALID_OPERATION;
+    }
+
+    status_t err = mLockedBuffer->unlock();
+    LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+    err = queueBuffer(mLockedBuffer.get());
+    LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+            mLockedBuffer->handle, strerror(-err));
+
+    mPostedBuffer = mLockedBuffer;
+    mLockedBuffer = 0;
+    return err;
+}
+
 }; // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 519b40e..2b8f204 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -613,4 +613,90 @@
     }
 }
 
+class MultiSurfaceTextureClientTest : public ::testing::Test {
+
+public:
+    MultiSurfaceTextureClientTest() :
+            mEglDisplay(EGL_NO_DISPLAY),
+            mEglContext(EGL_NO_CONTEXT) {
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            mEglSurfaces[i] = EGL_NO_CONTEXT;
+        }
+    }
+
+protected:
+
+    enum { NUM_SURFACE_TEXTURES = 32 };
+
+    virtual void SetUp() {
+        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+
+        EGLint majorVersion, minorVersion;
+        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        EGLConfig myConfig;
+        EGLint numConfigs = 0;
+        EGLint configAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+            EGL_NONE
+        };
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &myConfig, 1,
+                &numConfigs));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+                0);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
+
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            sp<SurfaceTexture> st(new SurfaceTexture(i));
+            sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+            mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
+                    static_cast<ANativeWindow*>(stc.get()), NULL);
+            ASSERT_EQ(EGL_SUCCESS, eglGetError());
+            ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
+        }
+    }
+
+    virtual void TearDown() {
+        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                EGL_NO_CONTEXT);
+
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            if (mEglSurfaces[i] != EGL_NO_SURFACE) {
+                eglDestroySurface(mEglDisplay, mEglSurfaces[i]);
+            }
+        }
+
+        if (mEglContext != EGL_NO_CONTEXT) {
+            eglDestroyContext(mEglDisplay, mEglContext);
+        }
+
+        if (mEglDisplay != EGL_NO_DISPLAY) {
+            eglTerminate(mEglDisplay);
+        }
+    }
+
+    EGLDisplay mEglDisplay;
+    EGLSurface mEglSurfaces[NUM_SURFACE_TEXTURES];
+    EGLContext mEglContext;
+};
+
+// XXX: This test is disabled because it causes a hang on some devices.  See bug
+// 5015672.
+TEST_F(MultiSurfaceTextureClientTest, DISABLED_MakeCurrentBetweenSurfacesWorks) {
+    for (int iter = 0; iter < 8; iter++) {
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            eglMakeCurrent(mEglDisplay, mEglSurfaces[i], mEglSurfaces[i],
+                    mEglContext);
+            glClear(GL_COLOR_BUFFER_BIT);
+            eglSwapBuffers(mEglDisplay, mEglSurfaces[i]);
+        }
+    }
+}
+
 } // namespace android
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 9c10c75..794747d 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -303,6 +303,10 @@
         case NATIVE_WINDOW_CONNECT:
         case NATIVE_WINDOW_DISCONNECT:
             break;
+        case NATIVE_WINDOW_LOCK:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_UNLOCK_AND_POST:
+            return INVALID_OPERATION;
         default:
             return NAME_NOT_FOUND;
     }
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 7b7ba74..178039c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -27,6 +27,8 @@
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 
+#include <gui/SurfaceTextureClient.h>
+
 #include <media/mediaplayer.h>
 #include <media/AudioTrack.h>
 
@@ -38,6 +40,7 @@
 #include <utils/String8.h>
 
 #include <system/audio.h>
+#include <system/window.h>
 
 namespace android {
 
@@ -194,13 +197,62 @@
     return mPlayer->getMetadata(update_only, apply_filter, metadata);
 }
 
+void MediaPlayer::disconnectNativeWindow() {
+    if (mConnectedWindow != NULL) {
+        status_t err = native_window_disconnect(mConnectedWindow.get(),
+                NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            LOGW("native_window_disconnect returned an error: %s (%d)",
+                    strerror(-err), err);
+        }
+    }
+    mConnectedWindow.clear();
+}
+
 status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
 {
     LOGV("setVideoSurface");
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return NO_INIT;
 
-    return mPlayer->setVideoSurface(surface);
+    sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder());
+    if (mConnectedWindowBinder == binder) {
+        return OK;
+    }
+
+    if (surface != NULL) {
+        status_t err = native_window_connect(surface.get(),
+                NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            // Note that we must do the reset before disconnecting from the ANW.
+            // Otherwise queue/dequeue calls could be made on the disconnected
+            // ANW, which may result in errors.
+            reset_l();
+
+            disconnectNativeWindow();
+
+            return err;
+        }
+    }
+
+    // Note that we must set the player's new surface before disconnecting the
+    // old one.  Otherwise queue/dequeue calls could be made on the disconnected
+    // ANW, which may result in errors.
+    status_t err = mPlayer->setVideoSurface(surface);
+
+    disconnectNativeWindow();
+
+    mConnectedWindow = surface;
+
+    if (err == OK) {
+        mConnectedWindowBinder = binder;
+    } else {
+        disconnectNativeWindow();
+    }
+
+    return err;
 }
 
 status_t MediaPlayer::setVideoSurfaceTexture(
@@ -210,7 +262,46 @@
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return NO_INIT;
 
-    return mPlayer->setVideoSurfaceTexture(surfaceTexture);
+    sp<IBinder> binder(surfaceTexture == NULL ? NULL :
+            surfaceTexture->asBinder());
+    if (mConnectedWindowBinder == binder) {
+        return OK;
+    }
+
+    sp<ANativeWindow> anw;
+    if (surfaceTexture != NULL) {
+        anw = new SurfaceTextureClient(surfaceTexture);
+        status_t err = native_window_connect(anw.get(),
+                NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            // Note that we must do the reset before disconnecting from the ANW.
+            // Otherwise queue/dequeue calls could be made on the disconnected
+            // ANW, which may result in errors.
+            reset_l();
+
+            disconnectNativeWindow();
+
+            return err;
+        }
+    }
+
+    // Note that we must set the player's new SurfaceTexture before
+    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
+    // on the disconnected ANW, which may result in errors.
+    status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture);
+
+    disconnectNativeWindow();
+
+    mConnectedWindow = anw;
+
+    if (err == OK) {
+        mConnectedWindowBinder = binder;
+    } else {
+        disconnectNativeWindow();
+    }
+
+    return err;
 }
 
 // must call with lock held
@@ -434,10 +525,8 @@
     return result;
 }
 
-status_t MediaPlayer::reset()
+status_t MediaPlayer::reset_l()
 {
-    LOGV("reset");
-    Mutex::Autolock _l(mLock);
     mLoop = false;
     if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
     mPrepareSync = false;
@@ -458,6 +547,13 @@
     return NO_ERROR;
 }
 
+status_t MediaPlayer::reset()
+{
+    LOGV("reset");
+    Mutex::Autolock _l(mLock);
+    return reset_l();
+}
+
 status_t MediaPlayer::setAudioStreamType(int type)
 {
     LOGV("MediaPlayer::setAudioStreamType");
diff --git a/media/libstagefright/codecs/aacenc/src/memalign.c b/media/libstagefright/codecs/aacenc/src/memalign.c
index 7d203527..44dd4ba 100644
--- a/media/libstagefright/codecs/aacenc/src/memalign.c
+++ b/media/libstagefright/codecs/aacenc/src/memalign.c
@@ -23,6 +23,11 @@
 
 
 #include	"memalign.h"
+#ifdef _MSC_VER
+#include	<stddef.h>
+#else
+#include	<stdint.h>
+#endif
 
 /*****************************************************************************
 *
@@ -66,8 +71,8 @@
 		pMemop->Set(CodecID, tmp, 0, size + alignment);
 
 		mem_ptr =
-			(unsigned char *) ((unsigned int) (tmp + alignment - 1) &
-					(~((unsigned int) (alignment - 1))));
+			(unsigned char *) ((intptr_t) (tmp + alignment - 1) &
+					(~((intptr_t) (alignment - 1))));
 
 		if (mem_ptr == tmp)
 			mem_ptr += alignment;
diff --git a/media/libstagefright/codecs/amrwbenc/src/cmnMemory.c b/media/libstagefright/codecs/amrwbenc/src/cmnMemory.c
deleted file mode 100644
index dd7c26d..0000000
--- a/media/libstagefright/codecs/amrwbenc/src/cmnMemory.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- ** Copyright 2003-2010, VisualOn, Inc.
- **
- ** 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.
- */
-/*******************************************************************************
-	File:		cmnMemory.c
-
-	Content:	sample code for memory operator implementation
-
-*******************************************************************************/
-#include "cmnMemory.h"
-
-#include <malloc.h>
-#if defined LINUX
-#include <string.h>
-#endif
-
-//VO_MEM_OPERATOR		g_memOP;
-
-VO_U32 cmnMemAlloc (VO_S32 uID,  VO_MEM_INFO * pMemInfo)
-{
-	if (!pMemInfo)
-		return VO_ERR_INVALID_ARG;
-
-	pMemInfo->VBuffer = malloc (pMemInfo->Size);
-	return 0;
-}
-
-VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pMem)
-{
-	free (pMem);
-	return 0;
-}
-
-VO_U32	cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize)
-{
-	memset (pBuff, uValue, uSize);
-	return 0;
-}
-
-VO_U32	cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
-{
-	memcpy (pDest, pSource, uSize);
-	return 0;
-}
-
-VO_U32	cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize)
-{
-	return 0;
-}
-
-VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize)
-{
-	return memcmp(pBuffer1, pBuffer2, uSize);
-}
-
-VO_U32	cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
-{
-	memmove (pDest, pSource, uSize);
-	return 0;
-}
-
diff --git a/media/libstagefright/codecs/common/cmnMemory.c b/media/libstagefright/codecs/common/cmnMemory.c
index dd7c26d..aa52bd9 100644
--- a/media/libstagefright/codecs/common/cmnMemory.c
+++ b/media/libstagefright/codecs/common/cmnMemory.c
@@ -21,10 +21,8 @@
 *******************************************************************************/
 #include "cmnMemory.h"
 
-#include <malloc.h>
-#if defined LINUX
+#include <stdlib.h>
 #include <string.h>
-#endif
 
 //VO_MEM_OPERATOR		g_memOP;
 
diff --git a/media/libstagefright/codecs/common/include/voType.h b/media/libstagefright/codecs/common/include/voType.h
index 70b2e83..5f659ab 100644
--- a/media/libstagefright/codecs/common/include/voType.h
+++ b/media/libstagefright/codecs/common/include/voType.h
@@ -101,7 +101,7 @@
    since the compiler does not support the way the component was written.
 */
 #ifndef VO_SKIP64BIT
-#ifdef _WIN32
+#ifdef _MSC_VER
 /** VO_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */
 typedef unsigned __int64  VO_U64;
 /** VO_S64 is a 64 bit signed quantity that is 64 bit word aligned */
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 2c0e88e..5c016c4 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -81,39 +81,9 @@
 
 int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
         ARect* inOutDirtyBounds) {
-    int type = -1;
-    if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &type) != 0 ||
-            type != NATIVE_WINDOW_SURFACE) {
-        return BAD_VALUE;
-    }
-
-    Region dirtyRegion;
-    Region* dirtyParam = NULL;
-    if (inOutDirtyBounds != NULL) {
-        dirtyRegion.set(*(Rect*)inOutDirtyBounds);
-        dirtyParam = &dirtyRegion;
-    }
-    
-    Surface::SurfaceInfo info;
-    status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam);
-    if (res != OK) {
-        return -1;
-    }
-    
-    outBuffer->width = (int32_t)info.w;
-    outBuffer->height = (int32_t)info.h;
-    outBuffer->stride = (int32_t)info.s;
-    outBuffer->format = (int32_t)info.format;
-    outBuffer->bits = info.bits;
-    
-    if (inOutDirtyBounds != NULL) {
-        *inOutDirtyBounds = dirtyRegion.getBounds();
-    }
-    
-    return 0;
+    return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
 }
 
 int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
-    status_t res = static_cast<Surface*>(window)->unlockAndPost();
-    return res == android::OK ? 0 : -1;
+    return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
 }
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 337fa96..2f4f2d3 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -99,10 +99,16 @@
  * width and height must be either both zero or both non-zero.
  *
  */
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
+        int32_t width, int32_t height, int32_t format);
 
 /**
  * Lock the window's next drawing surface for writing.
+ * inOutDirtyBounds is used as an in/out parameter, upon entering the
+ * function, it contains the dirty region, that is, the region the caller
+ * intends to redraw. When the function returns, inOutDirtyBounds is updated
+ * with the actual area the caller needs to redraw -- this region is often
+ * extended by ANativeWindow_lock.
  */
 int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
         ARect* inOutDirtyBounds);
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1123e16..6a199db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -226,7 +226,7 @@
 #ifndef EGL_ANDROID_image_native_buffer
 #define EGL_ANDROID_image_native_buffer 1
 struct ANativeWindowBuffer;
-#define EGL_NATIVE_BUFFER_ANDROID       0x3140  /* eglCreateImageKHR target */
+#define EGL_NATIVE_BUFFER_ANDROID               0x3140  /* eglCreateImageKHR target */
 #endif
 
 #ifndef EGL_ANDROID_swap_rectangle
@@ -237,6 +237,11 @@
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
 #endif
 
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID                  0x3142  /* EGLConfig attribute */
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/specs/EGL_ANDROID_recordable.txt b/opengl/specs/EGL_ANDROID_recordable.txt
index cf44465..8dbd26f 100644
--- a/opengl/specs/EGL_ANDROID_recordable.txt
+++ b/opengl/specs/EGL_ANDROID_recordable.txt
@@ -55,7 +55,7 @@
     Accepted by the <attribute> parameter of eglGetConfigAttrib and
     the <attrib_list> parameter of eglChooseConfig:
 
-        EGL_RECORDABLE_ANDROID                      0xXXXX
+        EGL_RECORDABLE_ANDROID                      0x3142
 
 Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
 
@@ -103,11 +103,38 @@
 
     RESOLVED: It should not affect sorting.  Some implementations may not have
     any drawback associated with using a recordable EGLConfig.  Such
-    implementations should not have to double-up some of their configs to  one sort earlier than .
-    Implementations that do have drawbacks can use the existing caveat
-    mechanism to report this drawback to the client.
+    implementations should not have to double-up some of their configs to  one
+    sort earlier than .  Implementations that do have drawbacks can use the
+    existing caveat mechanism to report this drawback to the client.
+
+    3. How is this extension expected to be implemented?
+
+    RESPONSE: There are two basic approaches to implementing this extension
+    that were considered during its design.  In both cases it is assumed that a
+    color space conversion must be performed at some point because most video
+    encoding formats use a YUV color space.  The two approaches are
+    distinguished by the point at which this color space conversion is
+    performed.
+
+    One approach involves performing the color space conversion as part of the
+    eglSwapBuffers call before queuing the rendered image to the ANativeWindow.
+    In this case, the VisualID of the EGLConfig would correspond to a YUV
+    Android HAL pixel format from which the video encoder can read.  The
+    EGLConfig would likely have the EGL_SLOW_CONFIG caveat because using that
+    config to render normal window contents would result in an RGB -> YUV color
+    space conversion when rendering the frame as well as a YUV -> RGB
+    conversion when compositing the window.
+
+    The other approach involves performing the color space conversion in the
+    video encoder.  In this case, the VisualID of the EGLConfig would
+    correspond to an RGB HAL pixel format from which the video encoder can
+    read.  The EGLConfig would likely not need to have any caveat set, as using
+    this config for normal window rendering would not have any added cost.
 
 Revision History
 
+#2 (Jamie Gennis, July 15, 2011)
+    - Added issue 3.
+
 #1 (Jamie Gennis, July 8, 2011)
     - Initial draft.
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml b/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml
deleted file mode 100644
index 0e58e12..0000000
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-	android:exitFadeDuration="@android:integer/config_mediumAnimTime">
-
-    <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
-
-    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
-    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
-    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
-    <item android:state_focused="true"                                                             android:drawable="@drawable/recents_thumbnail_bg_holo" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml b/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml
new file mode 100644
index 0000000..6cae2c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@drawable/recents_thumbnail_bg" android:id="@+id/base_layer"/>
+    <item android:drawable="@drawable/recents_thumbnail_overlay" android:id="@+id/overlay_layer"/>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
new file mode 100644
index 0000000..200bac4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+    <item android:drawable="@*android:color/transparent"/>
+</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index be4f1d7..8c29042 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -24,14 +24,15 @@
     android:layout_height="wrap_content"
     android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
 
-    <ImageView android:id="@+id/app_thumbnail"
+    <FrameLayout android:id="@+id/app_thumbnail"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
-        android:background="@drawable/recents_thumbnail_bg_selector"
+        android:clickable="true"
+        android:background="@drawable/recents_thumbnail_layers"
     />
 
     <ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index efdd9ac..20ef7cf 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -51,7 +51,6 @@
                 android:fadingEdge="horizontal"
                 android:scrollbars="none"
                 android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
-                android:listSelector="@drawable/recents_thumbnail_bg_selector"
                 android:layout_gravity="bottom|left"
                 android:orientation="horizontal"
                 android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index 76965c9..c705a69 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -24,13 +24,15 @@
     android:layout_height="wrap_content"
     android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
 
-    <ImageView android:id="@+id/app_thumbnail"
+    <FrameLayout android:id="@+id/app_thumbnail"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
+        android:clickable="true"
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
+        android:background="@drawable/recents_thumbnail_layers"
     />
 
     <ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index 28ef239..c680b8e 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -48,7 +48,6 @@
                 android:fadingEdge="vertical"
                 android:scrollbars="none"
                 android:fadingEdgeLength="@*android:dimen/status_bar_height"
-                android:listSelector="@drawable/recents_thumbnail_bg_selector"
                 android:layout_gravity="bottom|left"
                 android:clipToPadding="false"
                 android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 9687866..386ce30 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -24,13 +24,15 @@
     android:layout_height="wrap_content"
     android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
 
-    <ImageView android:id="@+id/app_thumbnail"
+    <FrameLayout android:id="@+id/app_thumbnail"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
+        android:clickable="true"
+        android:background="@drawable/recents_thumbnail_layers"
     />
 
     <ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 75fdc67..2c9a152 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -56,7 +56,6 @@
                 android:scrollbars="none"
                 android:fadingEdgeLength="20dip"
                 android:layout_gravity="bottom|left"
-                android:listSelector="@drawable/recents_thumbnail_bg_selector"
                 android:clipToPadding="false"
                 android:clipChildren="false">
 
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml b/packages/SystemUI/res/menu/recent_popup_menu.xml
similarity index 70%
rename from packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
rename to packages/SystemUI/res/menu/recent_popup_menu.xml
index f9bba2a..eecfb9a 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
+++ b/packages/SystemUI/res/menu/recent_popup_menu.xml
@@ -17,7 +17,7 @@
 ** limitations under the License.
 */
 -->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
-    <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
-</transition>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/recent_remove_item" android:title="@string/status_bar_recent_remove_item_title" />
+    <item android:id="@+id/recent_inspect_item" android:title="@string/status_bar_recent_inspect_item_title" />
+</menu>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 882455e..01cf2dc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -35,6 +35,14 @@
          shown again. [CHAR LIMIT=25] -->
     <string name="status_bar_please_disturb_button">Show notifications</string>
 
+    <!-- Title shown in recents popup for removing an application from the list -->
+    <string name="status_bar_recent_remove_item_title">Remove</string>
+
+    <!-- Title shown in recents popup for inspecting an application's properties -->
+    <string name="status_bar_recent_inspect_item_title">Inspect</string>
+
+
+
 
     <!-- The label in the bar at the top of the status bar when there are no notifications
          showing.  [CHAR LIMIT=40]-->
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index 37a9913..2d327c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -53,8 +53,6 @@
     void createAnimation(boolean appearing) {
         float start, end;
 
-        if (RecentsPanelView.DEBUG) Log.e(TAG, "createAnimation()", new Exception());
-
         // 0: on-screen
         // height: off-screen
         float y = mContentView.getTranslationY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 5d29e2a..797f94c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -26,5 +26,5 @@
 
     void handleOnClick(View selectedView);
     void handleSwipe(View selectedView, int direction);
-    void handleLongPress(View selectedView);
+    void handleLongPress(View selectedView, View anchorView);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index f984aac..2a5d1dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -20,6 +20,7 @@
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -30,7 +31,6 @@
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -42,10 +42,9 @@
 
 import com.android.systemui.R;
 
-public class RecentsHorizontalScrollView extends HorizontalScrollView
-        implements View.OnClickListener, View.OnTouchListener {
-    private static final boolean DEBUG_INVALIDATE = false;
+public class RecentsHorizontalScrollView extends HorizontalScrollView {
     private static final String TAG = RecentsPanelView.TAG;
+    private static final boolean DEBUG_INVALIDATE = false;
     private static final boolean DEBUG = RecentsPanelView.DEBUG;
     private LinearLayout mLinearLayout;
     private ActivityDescriptionAdapter mAdapter;
@@ -57,6 +56,15 @@
     private VelocityTracker mVelocityTracker;
     private float mDensityScale;
     private float mPagingTouchSlop;
+    private OnLongClickListener mOnLongClick = new OnLongClickListener() {
+        public boolean onLongClick(View v) {
+            final View anchorView = v.findViewById(R.id.app_description);
+            mCurrentView = v;
+            mCallback.handleLongPress(v, anchorView);
+            mCurrentView = null; // make sure we don't accept the return click from this
+            return true;
+        }
+    };
 
     public RecentsHorizontalScrollView(Context context) {
         this(context, null);
@@ -72,13 +80,12 @@
         return mLinearLayout.getWidth() - getWidth();
     }
 
-    public void update() {
+    private void update() {
         mLinearLayout.removeAllViews();
         for (int i = 0; i < mAdapter.getCount(); i++) {
-            View view = mAdapter.getView(i, null, mLinearLayout);
+            final View view = mAdapter.getView(i, null, mLinearLayout);
             view.setClickable(true);
-            view.setOnClickListener(this);
-            view.setOnTouchListener(this);
+            view.setOnLongClickListener(mOnLongClick);
             mLinearLayout.addView(view);
         }
         // Scroll to end after layout.
@@ -91,7 +98,20 @@
     }
 
     @Override
+    public void removeViewInLayout(final View view) {
+        ObjectAnimator anim = animateClosed(view, Constants.MAX_ESCAPE_ANIMATION_DURATION,
+                "y", view.getY(), view.getY() + view.getHeight());
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                RecentsHorizontalScrollView.super.removeView(view);
+            }
+        });
+        anim.start();
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
         }
@@ -100,6 +120,18 @@
             case MotionEvent.ACTION_DOWN:
                 mDragging = false;
                 mLastY = ev.getY();
+                final float x = ev.getX() + getScrollX();
+                final float y = ev.getY() + getScrollY();
+                mCurrentView = null;
+                for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+                    View item = mLinearLayout.getChildAt(i);
+                    if (x >= item.getLeft() && x < item.getRight()
+                            && y >= item.getTop() && y < item.getBottom()) {
+                        mCurrentView = item;
+                        if (DEBUG) Log.v(TAG, "Hit item " + item);
+                        break;
+                    }
+                }
                 break;
 
             case MotionEvent.ACTION_MOVE:
@@ -111,6 +143,9 @@
                 break;
 
             case MotionEvent.ACTION_UP:
+                if (mCurrentView != null) {
+                    mCallback.handleOnClick(mCurrentView);
+                }
                 mDragging = false;
                 break;
         }
@@ -125,7 +160,6 @@
         } else if (view.getY() < thumbHeight * (1.0f - Constants.ALPHA_FADE_START)) {
             result = 1.0f + (thumbHeight * Constants.ALPHA_FADE_START + view.getY()) / fadeHeight;
         }
-        if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
         return result;
     }
 
@@ -138,12 +172,12 @@
         mVelocityTracker.addMovement(ev);
 
         final View animView = mCurrentView;
-        // TODO: Cache thumbnail
-        final View thumb = animView.findViewById(R.id.app_thumbnail);
+
         switch (ev.getAction()) {
             case MotionEvent.ACTION_MOVE:
                 if (animView != null) {
                     final float delta = ev.getY() - mLastY;
+                    final View thumb = animView.findViewById(R.id.app_thumbnail);
                     animView.setY(animView.getY() + delta);
                     animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
                     invalidateGlobalRegion(animView);
@@ -167,35 +201,18 @@
                         long duration =
                             (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
                         duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
-                        anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
-                        anim.setInterpolator(new LinearInterpolator());
-                        final int swipeDirection = animView.getY() >= 0.0f ?
-                                RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
-                        anim.addListener(new AnimatorListener() {
-                            public void onAnimationStart(Animator animation) {
-                            }
-                            public void onAnimationRepeat(Animator animation) {
-                            }
-                            public void onAnimationEnd(Animator animation) {
-                                mLinearLayout.removeView(mCurrentView);
-                                mCallback.handleSwipe(animView, swipeDirection);
-                            }
-                            public void onAnimationCancel(Animator animation) {
-                                mLinearLayout.removeView(mCurrentView);
-                                mCallback.handleSwipe(animView, swipeDirection);
-                            }
-                        });
-                        anim.setDuration(duration);
+                        anim = animateClosed(animView, duration, "y", curY, newY);
                     } else { // Animate back to position
                         long duration = Math.abs(velocityY) > 0.0f ?
                                 (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
                                 : Constants.SNAP_BACK_DURATION;
                         duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
                         anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
-                        anim.setInterpolator(new DecelerateInterpolator(2.0f));
+                        anim.setInterpolator(new DecelerateInterpolator(4.0f));
                         anim.setDuration(duration);
                     }
 
+                    final View thumb = animView.findViewById(R.id.app_thumbnail);
                     anim.addUpdateListener(new AnimatorUpdateListener() {
                         public void onAnimationUpdate(ValueAnimator animation) {
                             animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
@@ -212,6 +229,26 @@
         return true;
     }
 
+    private ObjectAnimator animateClosed(final View animView, long duration,
+            String attr, float from, float to) {
+        ObjectAnimator anim = ObjectAnimator.ofFloat(animView, attr, from, to);
+        anim.setInterpolator(new LinearInterpolator());
+        final int swipeDirection = animView.getX() >= 0.0f ?
+                RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                mLinearLayout.removeView(animView);
+                mCallback.handleSwipe(animView, swipeDirection);
+            }
+            public void onAnimationCancel(Animator animation) {
+                mLinearLayout.removeView(animView);
+                mCallback.handleSwipe(animView, swipeDirection);
+            }
+        });
+        anim.setDuration(duration);
+        return anim;
+    }
+
     void invalidateGlobalRegion(View view) {
         RectF childBounds
                 = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
@@ -236,13 +273,8 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        LayoutInflater inflater = (LayoutInflater)
-                mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
         setScrollbarFadingEnabled(true);
-
         mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-
         final int leftPadding = mContext.getResources()
             .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
         setOverScrollEffectPadding(leftPadding, 0);
@@ -306,16 +338,7 @@
         mLinearLayout.setLayoutTransition(transition);
     }
 
-    public void onClick(View view) {
-        mCallback.handleOnClick(view);
-    }
-
     public void setCallback(RecentsCallback callback) {
         mCallback = callback;
     }
-
-    public boolean onTouch(View v, MotionEvent event) {
-        mCurrentView = v;
-        return false;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index a55fe9c..bc0a508 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -22,6 +22,7 @@
 import android.animation.Animator;
 import android.animation.LayoutTransition;
 import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -39,16 +40,22 @@
 import android.graphics.Shader.TileMode;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.BaseAdapter;
+import android.widget.Button;
 import android.widget.ImageView;
+import android.widget.PopupMenu;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
@@ -69,7 +76,7 @@
     private int mIconDpi;
     private View mRecentsScrim;
     private View mRecentsGlowView;
-    private View mRecentsContainer;
+    private ViewGroup mRecentsContainer;
     private Bitmap mGlowBitmap;
     // TODO: add these widgets attributes to the layout file
     private int mGlowBitmapPaddingLeftPx;
@@ -107,8 +114,18 @@
         }
     };
 
+    private final class OnLongClickDelegate implements View.OnLongClickListener {
+        View mOtherView;
+        OnLongClickDelegate(View other) {
+            mOtherView = other;
+        }
+        public boolean onLongClick(View v) {
+            return mOtherView.performLongClick();
+        }
+    }
+
     /* package */ final static class ViewHolder {
-        ImageView thumbnailView;
+        View thumbnailView;
         ImageView iconView;
         TextView labelView;
         TextView descriptionView;
@@ -139,7 +156,7 @@
             if (convertView == null) {
                 convertView = mInflater.inflate(R.layout.status_bar_recent_item, null);
                 holder = new ViewHolder();
-                holder.thumbnailView = (ImageView) convertView.findViewById(R.id.app_thumbnail);
+                holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
                 holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
                 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
                 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -153,11 +170,12 @@
 
             final ActivityDescription activityDescription = mActivityDescriptions.get(activityId);
             final Bitmap thumb = activityDescription.thumbnail;
-            holder.thumbnailView.setImageBitmap(compositeBitmap(mGlowBitmap, thumb));
+            updateDrawable(holder.thumbnailView, compositeBitmap(mGlowBitmap, thumb));
             holder.iconView.setImageDrawable(activityDescription.icon);
             holder.labelView.setText(activityDescription.label);
             holder.descriptionView.setText(activityDescription.description);
             holder.thumbnailView.setTag(activityDescription);
+            holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
             holder.activityDescription = activityDescription;
 
             return convertView;
@@ -174,6 +192,20 @@
         return x >= l && x < r && y >= t && y < b;
     }
 
+    private void updateDrawable(View thumbnailView, Bitmap bitmap) {
+        Drawable d = thumbnailView.getBackground();
+        if (d instanceof LayerDrawable) {
+            LayerDrawable layerD = (LayerDrawable) d;
+            Drawable thumb = layerD.findDrawableByLayerId(R.id.base_layer);
+            if (thumb != null) {
+                layerD.setDrawableByLayerId(R.id.base_layer,
+                        new BitmapDrawable(getResources(), bitmap));
+                return;
+            }
+        }
+        Log.w(TAG, "Failed to update drawable");
+    }
+
     public void show(boolean show, boolean animate) {
         if (animate) {
             if (mShowing != show) {
@@ -260,7 +292,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mRecentsContainer = findViewById(R.id.recents_container);
+        mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
         mListAdapter = new ActivityDescriptionAdapter(mContext);
         if (mRecentsContainer instanceof RecentsListView) {
             RecentsListView listView = (RecentsListView) mRecentsContainer;
@@ -503,7 +535,35 @@
         am.removeTask(ad.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
-    public void handleLongPress(View selectedView) {
-        // TODO show context menu : "Remove from list", "Show properties"
+    private void startApplicationDetailsActivity(String packageName) {
+        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+                Uri.fromParts("package", packageName, null));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getContext().startActivity(intent);
+    }
+
+    public void handleLongPress(final View selectedView, final View anchorView) {
+        PopupMenu popup = new PopupMenu(mContext, anchorView == null ? selectedView : anchorView);
+        popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
+        popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+            public boolean onMenuItemClick(MenuItem item) {
+                if (item.getItemId() == R.id.recent_remove_item) {
+                    mRecentsContainer.removeViewInLayout(selectedView);
+                } else if (item.getItemId() == R.id.recent_inspect_item) {
+                    ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
+                    if (viewHolder != null) {
+                        final ActivityDescription ad = viewHolder.activityDescription;
+                        startApplicationDetailsActivity(ad.packageName);
+                        mBar.animateCollapse();
+                    } else {
+                        throw new IllegalStateException("Oops, no tag on view " + selectedView);
+                    }
+                } else {
+                    return false;
+                }
+                return true;
+            }
+        });
+        popup.show();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 27bb0b5..47ee4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -20,6 +20,7 @@
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -42,8 +43,7 @@
 
 import com.android.systemui.R;
 
-public class RecentsVerticalScrollView extends ScrollView
-        implements View.OnClickListener, View.OnTouchListener {
+public class RecentsVerticalScrollView extends ScrollView {
     private static final String TAG = RecentsPanelView.TAG;
     private static final boolean DEBUG_INVALIDATE = false;
     private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -57,6 +57,15 @@
     private VelocityTracker mVelocityTracker;
     private float mDensityScale;
     private float mPagingTouchSlop;
+    private OnLongClickListener mOnLongClick = new OnLongClickListener() {
+        public boolean onLongClick(View v) {
+            final View anchorView = v.findViewById(R.id.app_description);
+            mCurrentView = v;
+            mCallback.handleLongPress(v, anchorView);
+            mCurrentView = null; // make sure we don't accept the return click from this
+            return true;
+        }
+    };
 
     public RecentsVerticalScrollView(Context context) {
         this(context, null);
@@ -72,13 +81,12 @@
         return mLinearLayout.getHeight() - getHeight();
     }
 
-    public void update() {
+    private void update() {
         mLinearLayout.removeAllViews();
         for (int i = 0; i < mAdapter.getCount(); i++) {
-            View view = mAdapter.getView(i, null, mLinearLayout);
+            final View view = mAdapter.getView(i, null, mLinearLayout);
             view.setClickable(true);
-            view.setOnClickListener(this);
-            view.setOnTouchListener(this);
+            view.setOnLongClickListener(mOnLongClick);
             mLinearLayout.addView(view);
         }
         // Scroll to end after layout.
@@ -91,7 +99,20 @@
     }
 
     @Override
+    public void removeViewInLayout(final View view) {
+        ObjectAnimator anim = animateClosed(view, Constants.MAX_ESCAPE_ANIMATION_DURATION,
+                "x", view.getX(), view.getX() + view.getWidth());
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                RecentsVerticalScrollView.super.removeView(view);
+            }
+        });
+        anim.start();
+    }
+
+    @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
         }
@@ -100,6 +121,18 @@
             case MotionEvent.ACTION_DOWN:
                 mDragging = false;
                 mLastX = ev.getX();
+                final float x = ev.getX() + getScrollX();
+                final float y = ev.getY() + getScrollY();
+                mCurrentView = null;
+                for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+                    View item = mLinearLayout.getChildAt(i);
+                    if (x >= item.getLeft() && x < item.getRight()
+                            && y >= item.getTop() && y < item.getBottom()) {
+                        mCurrentView = item;
+                        Log.v(TAG, "Hit item " + item);
+                        break;
+                    }
+                }
                 break;
 
             case MotionEvent.ACTION_MOVE:
@@ -111,6 +144,9 @@
                 break;
 
             case MotionEvent.ACTION_UP:
+                if (mCurrentView != null) {
+                    mCallback.handleOnClick(mCurrentView);
+                }
                 mDragging = false;
                 break;
         }
@@ -125,7 +161,6 @@
         } else if (view.getX() < thumbWidth* (1.0f - Constants.ALPHA_FADE_START)) {
             result = 1.0f + (thumbWidth*Constants.ALPHA_FADE_START + view.getX()) / fadeWidth;
         }
-        if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
         return result;
     }
 
@@ -138,12 +173,12 @@
         mVelocityTracker.addMovement(ev);
 
         final View animView = mCurrentView;
-        // TODO: Cache thumbnail
-        final View thumb = animView.findViewById(R.id.app_thumbnail);
+
         switch (ev.getAction()) {
             case MotionEvent.ACTION_MOVE:
                 if (animView != null) {
                     final float delta = ev.getX() - mLastX;
+                    final View thumb = animView.findViewById(R.id.app_thumbnail);
                     animView.setX(animView.getX() + delta);
                     animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
                     invalidateGlobalRegion(animView);
@@ -163,29 +198,11 @@
                     final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
                     if (Math.abs(velocityX) > Math.abs(velocityY)
                             && Math.abs(velocityX) > maxVelocity
-                            && (velocityX > 0.0f) == (animView.getX() >= 0)) {
+                            && (velocityX >= 0.0f) == (animView.getX() >= 0)) {
                         long duration =
                             (long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
                         duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
-                        anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
-                        anim.setInterpolator(new LinearInterpolator());
-                        final int swipeDirection = animView.getX() >= 0.0f ?
-                                RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
-                        anim.addListener(new AnimatorListener() {
-                            public void onAnimationStart(Animator animation) {
-                            }
-                            public void onAnimationRepeat(Animator animation) {
-                            }
-                            public void onAnimationEnd(Animator animation) {
-                                mLinearLayout.removeView(mCurrentView);
-                                mCallback.handleSwipe(animView, swipeDirection);
-                            }
-                            public void onAnimationCancel(Animator animation) {
-                                mLinearLayout.removeView(mCurrentView);
-                                mCallback.handleSwipe(animView, swipeDirection);
-                            }
-                        });
-                        anim.setDuration(duration);
+                        anim = animateClosed(animView, duration, "x", curX, newX);
                     } else { // Animate back to position
                         long duration = Math.abs(velocityX) > 0.0f ?
                                 (long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
@@ -196,6 +213,7 @@
                         anim.setDuration(duration);
                     }
 
+                    final View thumb = animView.findViewById(R.id.app_thumbnail);
                     anim.addUpdateListener(new AnimatorUpdateListener() {
                         public void onAnimationUpdate(ValueAnimator animation) {
                             animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
@@ -212,6 +230,26 @@
         return true;
     }
 
+    private ObjectAnimator animateClosed(final View animView, long duration,
+            String attr, float from, float to) {
+        ObjectAnimator anim = ObjectAnimator.ofFloat(animView, attr, from, to);
+        anim.setInterpolator(new LinearInterpolator());
+        final int swipeDirection = animView.getX() >= 0.0f ?
+                RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                mLinearLayout.removeView(animView);
+                mCallback.handleSwipe(animView, swipeDirection);
+            }
+            public void onAnimationCancel(Animator animation) {
+                mLinearLayout.removeView(animView);
+                mCallback.handleSwipe(animView, swipeDirection);
+            }
+        });
+        anim.setDuration(duration);
+        return anim;
+    }
+
     void invalidateGlobalRegion(View view) {
         RectF childBounds
                 = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
@@ -236,13 +274,8 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        LayoutInflater inflater = (LayoutInflater)
-                mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
         setScrollbarFadingEnabled(true);
-
         mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-
         final int leftPadding = mContext.getResources()
             .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
         setOverScrollEffectPadding(leftPadding, 0);
@@ -306,16 +339,7 @@
         mLinearLayout.setLayoutTransition(transition);
     }
 
-    public void onClick(View view) {
-        mCallback.handleOnClick(view);
-    }
-
     public void setCallback(RecentsCallback callback) {
         mCallback = callback;
     }
-
-    public boolean onTouch(View v, MotionEvent event) {
-        mCurrentView = v;
-        return false;
-    }
 }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9b09983..0eff776 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -502,77 +502,82 @@
 
 // ----------------------------------------------------------------------------
 
-// set the Surface that the preview will use
-status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
-    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
+static void disconnectWindow(const sp<ANativeWindow>& window) {
+    if (window != 0) {
+        status_t result = native_window_disconnect(window.get(),
+                NATIVE_WINDOW_API_CAMERA);
+        if (result != NO_ERROR) {
+            LOGW("native_window_disconnect failed: %s (%d)", strerror(-result),
+                    result);
+        }
+    }
+}
+
+status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder,
+        const sp<ANativeWindow>& window) {
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    result = NO_ERROR;
-
     // return if no change in surface.
-    sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
     if (binder == mSurface) {
-        return result;
+        return NO_ERROR;
     }
 
-    if (mSurface != 0) {
-        LOG1("clearing old preview surface %p", mSurface.get());
-    }
-    mSurface = binder;
-    mPreviewWindow = surface;
-
-    // If preview has been already started, register preview
-    // buffers now.
-    if (mHardware->previewEnabled()) {
-        if (mPreviewWindow != 0) {
-            native_window_set_buffers_transform(mPreviewWindow.get(),
-                                                mOrientation);
-            result = mHardware->setPreviewWindow(mPreviewWindow);
+    if (window != 0) {
+        result = native_window_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
+        if (result != NO_ERROR) {
+            LOGE("native_window_connect failed: %s (%d)", strerror(-result),
+                    result);
+            return result;
         }
     }
 
+    // If preview has been already started, register preview buffers now.
+    if (mHardware->previewEnabled()) {
+        if (window != 0) {
+            native_window_set_buffers_transform(window.get(), mOrientation);
+            result = mHardware->setPreviewWindow(window);
+        }
+    }
+
+    if (result == NO_ERROR) {
+        // Everything has succeeded.  Disconnect the old window and remember the
+        // new window.
+        disconnectWindow(mPreviewWindow);
+        mSurface = binder;
+        mPreviewWindow = window;
+    } else {
+        // Something went wrong after we connected to the new window, so
+        // disconnect here.
+        disconnectWindow(window);
+    }
+
     return result;
 }
 
+// set the Surface that the preview will use
+status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
+    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
+
+    sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
+    sp<ANativeWindow> window(surface);
+    return setPreviewWindow(binder, window);
+}
+
 // set the SurfaceTexture that the preview will use
 status_t CameraService::Client::setPreviewTexture(
         const sp<ISurfaceTexture>& surfaceTexture) {
     LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
             getCallingPid());
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
 
-    // return if no change in surface.
-    // asBinder() is safe on NULL (returns NULL)
-    if (surfaceTexture->asBinder() == mSurface) {
-        return result;
-    }
-
-    if (mSurface != 0) {
-        LOG1("clearing old preview surface %p", mSurface.get());
-    }
-    mSurface = surfaceTexture->asBinder();
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
     if (surfaceTexture != 0) {
-        mPreviewWindow = new SurfaceTextureClient(surfaceTexture);
-    } else {
-        mPreviewWindow = 0;
+        binder = surfaceTexture->asBinder();
+        window = new SurfaceTextureClient(surfaceTexture);
     }
-
-    // If preview has been already started, set overlay or register preview
-    // buffers now.
-    if (mHardware->previewEnabled()) {
-        // XXX: What if the new preview window is 0?
-        if (mPreviewWindow != 0) {
-            native_window_set_buffers_transform(mPreviewWindow.get(),
-                                                mOrientation);
-            result = mHardware->setPreviewWindow(mPreviewWindow);
-        }
-    }
-
-    return result;
+    return setPreviewWindow(binder, window);
 }
 
 // set the preview callback flag to affect how the received frames from
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 5e2d571..c5fefb8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -161,6 +161,10 @@
 
         int                     getOrientation(int orientation, bool mirror);
 
+        status_t                setPreviewWindow(
+                                    const sp<IBinder>& binder,
+                                    const sp<ANativeWindow>& window);
+
         // these are initialized in the constructor.
         sp<CameraService>               mCameraService;  // immutable after constructor
         sp<ICameraClient>               mCameraClient;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index a8dc885..bb9d15b 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -127,13 +127,15 @@
 
     private int mHandledFeedbackTypes = 0;
 
-    private boolean mIsEnabled;
+    private boolean mIsAccessibilityEnabled;
+
+    private boolean mIsTouchExplorationRequested;
 
     private AccessibilityInputFilter mInputFilter;
 
     private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>();
 
-    private boolean mHasInputFilter;
+    private boolean mIsTouchExplorationEnabled;
 
     private final WindowManagerService mWindowManagerService;
 
@@ -230,16 +232,21 @@
                 if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
                     synchronized (mLock) {
                         populateAccessibilityServiceListLocked();
-                        // get the accessibility enabled setting on boot
-                        mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+                        // get accessibility enabled setting on boot
+                        mIsAccessibilityEnabled = Settings.Secure.getInt(
+                                mContext.getContentResolver(),
                                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-
                         // if accessibility is enabled inform our clients we are on
-                        if (mIsEnabled) {
-                            updateClientsLocked();
+                        if (mIsAccessibilityEnabled) {
+                            sendAccessibilityEnabledToClientsLocked();
                         }
-
                         manageServicesLocked();
+
+                        // get touch exploration enabled setting on boot
+                        mIsTouchExplorationRequested = Settings.Secure.getInt(
+                                mContext.getContentResolver(),
+                                Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
+                        updateTouchExplorationEnabledLocked();
                     }
                     
                     return;
@@ -264,29 +271,48 @@
     private void registerSettingsContentObservers() {
         ContentResolver contentResolver = mContext.getContentResolver();
 
-        Uri enabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_ENABLED);
-        contentResolver.registerContentObserver(enabledUri, false,
+        Uri accessibilityEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_ENABLED);
+        contentResolver.registerContentObserver(accessibilityEnabledUri, false,
             new ContentObserver(new Handler()) {
                 @Override
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
 
                     synchronized (mLock) {
-                        mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+                        mIsAccessibilityEnabled = Settings.Secure.getInt(
+                                mContext.getContentResolver(),
                                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-                        if (mIsEnabled) {
+                        if (mIsAccessibilityEnabled) {
                             manageServicesLocked();
                         } else {
                             unbindAllServicesLocked();
                         }
-                        updateClientsLocked();
+                        sendAccessibilityEnabledToClientsLocked();
                     }
                 }
             });
 
-        Uri providersUri =
+        Uri touchExplorationRequestedUri = Settings.Secure.getUriFor(
+                Settings.Secure.TOUCH_EXPLORATION_REQUESTED);
+        contentResolver.registerContentObserver(touchExplorationRequestedUri, false,
+                new ContentObserver(new Handler()) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        super.onChange(selfChange);
+
+                        synchronized (mLock) {
+                            mIsTouchExplorationRequested = Settings.Secure.getInt(
+                                    mContext.getContentResolver(),
+                                    Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
+                            updateTouchExplorationEnabledLocked();
+                        }
+                    }
+                });
+
+        Uri accessibilityServicesUri =
             Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
-        contentResolver.registerContentObserver(providersUri, false,
+        contentResolver.registerContentObserver(accessibilityServicesUri, false,
             new ContentObserver(new Handler()) {
                 @Override
                 public void onChange(boolean selfChange) {
@@ -312,7 +338,7 @@
                     }
                 }
             }, 0);
-            return mIsEnabled;
+            return mIsAccessibilityEnabled;
         }
     }
 
@@ -602,7 +628,7 @@
             service.linkToOwnDeath();
             mServices.add(service);
             mComponentNameToServiceMap.put(service.mComponentName, service);
-            updateInputFilterLocked();
+            updateTouchExplorationEnabledLocked();
         } catch (RemoteException e) {
             /* do nothing */
         }
@@ -622,7 +648,7 @@
         mComponentNameToServiceMap.remove(service.mComponentName);
         mHandler.removeMessages(service.mId);
         service.unlinkToOwnDeath();
-        updateInputFilterLocked();
+        updateTouchExplorationEnabledLocked();
         return removed;
     }
 
@@ -727,7 +753,7 @@
             Set<ComponentName> enabledServices) {
 
         Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
-        boolean isEnabled = mIsEnabled;
+        boolean isEnabled = mIsAccessibilityEnabled;
 
         for (int i = 0, count = installedServices.size(); i < count; i++) {
             AccessibilityServiceInfo installedService = installedServices.get(i);
@@ -741,7 +767,7 @@
                         service = new Service(componentName, installedService, false);
                     }
                     service.bind();
-                } else if (!enabledServices.contains(componentName)) {
+                } else {
                     if (service != null) {
                         service.unbind();
                     }
@@ -757,10 +783,10 @@
     /**
      * Updates the state of {@link android.view.accessibility.AccessibilityManager} clients.
      */
-    private void updateClientsLocked() {
+    private void sendAccessibilityEnabledToClientsLocked() {
         for (int i = 0, count = mClients.size(); i < count; i++) {
             try {
-                mClients.get(i).setEnabled(mIsEnabled);
+                mClients.get(i).setEnabled(mIsAccessibilityEnabled);
             } catch (RemoteException re) {
                 mClients.remove(i);
                 count--;
@@ -770,29 +796,48 @@
     }
 
     /**
-     * Updates the input filter state. The filter is enabled if accessibility
-     * is enabled and there is at least one accessibility service providing
-     * spoken feedback.
+     * Sends the touch exploration state to clients.
      */
-    private void updateInputFilterLocked() {
-        if (mIsEnabled) {
-            final boolean hasSpokenFeedbackServices = !getEnabledAccessibilityServiceList(
-                    AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
-            if (hasSpokenFeedbackServices) {
-                if (mHasInputFilter) {
-                    return;
+    private void sendTouchExplorationEnabledToClientsLocked() {
+        for (int i = 0, count = mClients.size(); i < count; i++) {
+            try {
+                mClients.get(i).setTouchExplorationEnabled(mIsTouchExplorationEnabled);
+            } catch (RemoteException re) {
+                mClients.remove(i);
+                count--;
+                i--;
+            }
+        }
+    }
+
+    /**
+     * Updates the touch exploration state. Touch exploration is enabled if it
+     * is requested, accessibility is on and there is at least one enabled
+     * accessibility service providing spoken feedback.
+     */
+    private void updateTouchExplorationEnabledLocked() {
+        if (mIsAccessibilityEnabled && mIsTouchExplorationRequested) {
+            final boolean hasSpeakingServicesEnabled = !getEnabledAccessibilityServiceList(
+                     AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
+            if (!mIsTouchExplorationEnabled) {
+                if (!hasSpeakingServicesEnabled) {
+                     return;
                 }
                 if (mInputFilter == null) {
                     mInputFilter = new AccessibilityInputFilter(mContext);
                 }
                 mWindowManagerService.setInputFilter(mInputFilter);
-                mHasInputFilter = true;
+                mIsTouchExplorationEnabled = true;
+                sendTouchExplorationEnabledToClientsLocked();
+                return;
+            } else if (hasSpeakingServicesEnabled) {
                 return;
             }
         }
-        if (mHasInputFilter) {
+        if (mIsTouchExplorationEnabled) {
             mWindowManagerService.setInputFilter(null);
-            mHasInputFilter = false;
+            mIsTouchExplorationEnabled = false;
+            sendTouchExplorationEnabledToClientsLocked();
         }
     }
 
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 3139798..c80cd0a 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -473,10 +473,7 @@
                 case MSG_SET_CURRENT_FUNCTION:
                     String function = (String)msg.obj;
                     boolean makeDefault = (msg.arg1 == 1);
-                    if (makeDefault) {
-                        if (function == null) {
-                            throw new NullPointerException();
-                        }
+                    if (function != null && makeDefault) {
                         if (mAdbEnabled) {
                             function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
                         }
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index 302a2d6..1234bfd 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -542,6 +542,9 @@
         public void setEnabled(boolean enabled) {
             mIsEnabled = enabled;
         }
+
+        public void setTouchExplorationEnabled(boolean enabled) {
+        }
     }
 
     /**
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index 4f17e52..27e1887 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -168,15 +168,11 @@
         drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
 
         paint.setColor(Color.WHITE);
-//        char[] glyphs = new char[2*length];
-//        int count = getGlyphs(text, glyphs, dir);
-//
-//        logGlypths(glyphs, count);
-//        drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
 
-        Log.v(TAG, "START -- drawTextWithGlyphs");
-        drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir);
-        Log.v(TAG, "END   -- drawTextWithGlyphs");
+        Log.v(TAG, "START -- drawText");
+        setPaintDir(paint, dir);
+        canvas.drawText(text, x, y + currentTextSize, this.paint);
+        Log.v(TAG, "END   -- drawText");
 
         // Restore old paint properties
         paint.setFakeBoldText(oldFakeBold);
@@ -190,26 +186,6 @@
         paint.setBidiFlags(dir);
     }
 
-    private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
-        canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
-    }
-
-    private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) {
-        setPaintDir(paint, dir);
-        canvas.drawTextWithGlyphs(text, x, y, paint);
-    }
-
-    private void logGlypths(char[] glyphs, int count) {
-        Log.v(TAG, "GlyphIds - count=" + count);
-        for (int n = 0; n < count; n++) {
-            Log.v(TAG, "GlyphIds - Id[" + n + "]="+ (int)glyphs[n]);
-        }
-    }
-
-    private int getGlyphs(String text, char[] glyphs, int dir) {
-        return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
-    }
-
     private void drawInsideRect(Canvas canvas, int color) {
         paint.setColor(color);
         int width = getWidth();
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index af5006f..38a85a3 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -95,9 +95,7 @@
         }
         {
             Space v = new Space(context);
-            {
-                vg.addView(v, new LayoutParams(row5, col3));
-            }
+            vg.addView(v, new LayoutParams(row5, col3));
         }
         {
             Button v = new Button(context);
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 32a6a65..9fcd05a 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -94,6 +94,15 @@
         </activity>
 
         <activity
+                android:name="CanvasTextureViewActivity"
+                android:label="_CanvasTextureView">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
                 android:name="GLTextureViewActivity"
                 android:label="_TextureViewGL">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
new file mode 100644
index 0000000..4d7f042
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class CanvasTextureViewActivity extends Activity
+        implements TextureView.SurfaceTextureListener {
+    private TextureView mTextureView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FrameLayout content = new FrameLayout(this);
+
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+
+        content.addView(mTextureView, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER));
+        setContentView(content);
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        Canvas c = mTextureView.lockCanvas();
+        try {
+            c.drawColor(0xff00ff00);
+        } finally {
+            mTextureView.unlockCanvasAndPost(c);
+        }
+
+        c = mTextureView.lockCanvas(new Rect(100, 100, 200, 200));
+        try {
+            c.drawColor(0xff0000ff);
+        } finally {
+            mTextureView.unlockCanvasAndPost(c);
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        // Ignored
+    }
+
+    @Override
+    public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        // Ignored
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+        // Ignored
+    }
+}