Merge "Add C code to use BDADDR_ANY macro properly.  The macro expands into code that is not valid C++.  So we need to use a C helper."
diff --git a/api/current.txt b/api/current.txt
index d85873d..e4a1bc6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -207,6 +207,7 @@
     field public static final int actionModeCutDrawable = 16843537; // 0x1010311
     field public static final int actionModePasteDrawable = 16843539; // 0x1010313
     field public static final int actionModeSelectAllDrawable = 16843647; // 0x101037f
+    field public static final int actionModeStyle = 16843688; // 0x10103a8
     field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
     field public static final int actionProviderClass = 16843677; // 0x101039d
     field public static final int actionViewClass = 16843516; // 0x10102fc
@@ -1823,6 +1824,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();
@@ -13927,6 +13929,10 @@
   public static class Debug.MemoryInfo implements android.os.Parcelable {
     ctor public Debug.MemoryInfo();
     method public int describeContents();
+    method public static java.lang.String getOtherLabel(int);
+    method public int getOtherPrivateDirty(int);
+    method public int getOtherPss(int);
+    method public int getOtherSharedDirty(int);
     method public int getTotalPrivateDirty();
     method public int getTotalPss();
     method public int getTotalSharedDirty();
@@ -16698,6 +16704,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";
@@ -20488,6 +20495,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);
   }
@@ -20727,11 +20742,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);
@@ -20746,11 +20762,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);
@@ -20762,11 +20779,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);
@@ -22030,9 +22048,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 {
@@ -23261,6 +23282,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);
   }
@@ -23297,6 +23319,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/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dd1c275..b42f1c5 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -805,6 +805,7 @@
             Vector<CodecCapabilities> results;
             CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
                                  true, // queryDecoders
+                                 false, // hwCodecOnly
                                  &results), (status_t)OK);
 
             for (size_t i = 0; i < results.size(); ++i) {
@@ -844,7 +845,12 @@
 
         for (List<IOMX::ComponentInfo>::iterator it = list.begin();
              it != list.end(); ++it) {
-            printf("%s\n", (*it).mName.string());
+            printf("%s\t Roles: ", (*it).mName.string());
+            for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
+                    itRoles != (*it).mRoles.end() ; ++itRoles) {
+                printf("%s\t", (*itRoles).string());
+            }
+            printf("\n");
         }
     }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index ef4adca..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() {
@@ -193,8 +198,6 @@
         mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
         mResolveInfo = resolveInfo;
 
-        String settingsActivityName = null;
-        boolean retrieveScreenContent = false;
         XmlResourceParser parser = null;
 
         try {
@@ -242,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: "
@@ -315,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() {
@@ -331,6 +348,7 @@
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
         parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+        parcel.writeString(mDescription);
     }
 
     private void initFromParcel(Parcel parcel) {
@@ -343,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/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8994b17..f6cd866 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -70,7 +70,7 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewManager;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
@@ -413,10 +413,10 @@
     native private void dumpGraphicsInfo(FileDescriptor fd);
 
     private final class ApplicationThread extends ApplicationThreadNative {
-        private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
-        private static final String ONE_COUNT_COLUMN = "%17s %8d";
-        private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
-        private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d";
+        private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
+        private static final String ONE_COUNT_COLUMN = "%21s %8d";
+        private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
+        private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";
         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
         // Formatting for checkin service - update version if row format changes
@@ -729,12 +729,17 @@
         }
 
         @Override
-        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (args != null && args.length == 1 && args[0].equals("graphics")) {
+        public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) {
+            FileOutputStream fout = new FileOutputStream(fd);
+            PrintWriter pw = new PrintWriter(fout);
+            try {
+                return dumpMemInfo(fd, pw, args);
+            } finally {
                 pw.flush();
-                dumpGraphicsInfo(fd);
-                return;
             }
+        }
+
+        private Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, PrintWriter pw, String[] args) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -742,14 +747,6 @@
             Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
             Debug.getMemoryInfo(memInfo);
 
-            final int nativeShared = memInfo.nativeSharedDirty;
-            final int dalvikShared = memInfo.dalvikSharedDirty;
-            final int otherShared = memInfo.otherSharedDirty;
-
-            final int nativePrivate = memInfo.nativePrivateDirty;
-            final int dalvikPrivate = memInfo.dalvikPrivateDirty;
-            final int otherPrivate = memInfo.otherPrivateDirty;
-
             Runtime runtime = Runtime.getRuntime();
 
             long dalvikMax = runtime.totalMemory() / 1024;
@@ -813,16 +810,18 @@
                 pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
 
                 // Heap info - shared
-                pw.print(nativeShared); pw.print(',');
-                pw.print(dalvikShared); pw.print(',');
-                pw.print(otherShared); pw.print(',');
-                pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
+                pw.print(memInfo.nativeSharedDirty); pw.print(',');
+                pw.print(memInfo.dalvikSharedDirty); pw.print(',');
+                pw.print(memInfo.otherSharedDirty); pw.print(',');
+                pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
+                        + memInfo.otherSharedDirty); pw.print(',');
 
                 // Heap info - private
-                pw.print(nativePrivate); pw.print(',');
-                pw.print(dalvikPrivate); pw.print(',');
-                pw.print(otherPrivate); pw.print(',');
-                pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
+                pw.print(memInfo.nativePrivateDirty); pw.print(',');
+                pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
+                pw.print(memInfo.otherPrivateDirty); pw.print(',');
+                pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
+                        + memInfo.otherPrivateDirty); pw.print(',');
 
                 // Object counts
                 pw.print(viewInstanceCount); pw.print(',');
@@ -850,24 +849,38 @@
                     pw.print(',');
                 }
 
-                return;
+                return memInfo;
             }
 
             // otherwise, show human-readable format
-            printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
-            printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
-            printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
-                    nativeAllocated + dalvikAllocated);
-            printRow(pw, HEAP_COLUMN, "free:", nativeFree, dalvikFree, "N/A",
-                    nativeFree + dalvikFree);
+            printRow(pw, HEAP_COLUMN, "", "", "Shared", "Private", "Heap", "Heap", "Heap");
+            printRow(pw, HEAP_COLUMN, "", "Pss", "Dirty", "Dirty", "Size", "Alloc", "Free");
+            printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
+                    "------");
+            printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSharedDirty,
+                    memInfo.nativePrivateDirty, nativeMax, nativeAllocated, nativeFree);
+            printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSharedDirty,
+                    memInfo.dalvikPrivateDirty, dalvikMax, dalvikAllocated, dalvikFree);
 
-            printRow(pw, HEAP_COLUMN, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
-                    memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
+            int otherPss = memInfo.otherPss;
+            int otherSharedDirty = memInfo.otherSharedDirty;
+            int otherPrivateDirty = memInfo.otherPrivateDirty;
 
-            printRow(pw, HEAP_COLUMN, "(shared dirty):", nativeShared, dalvikShared, otherShared,
-                    nativeShared + dalvikShared + otherShared);
-            printRow(pw, HEAP_COLUMN, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
-                    nativePrivate + dalvikPrivate + otherPrivate);
+            for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+                printRow(pw, HEAP_COLUMN, memInfo.getOtherLabel(i),
+                        memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
+                        memInfo.getOtherPrivateDirty(i), "", "", "");
+                otherPss -= memInfo.getOtherPss(i);
+                otherSharedDirty -= memInfo.getOtherSharedDirty(i);
+                otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
+            }
+
+            printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSharedDirty,
+                    otherPrivateDirty, "", "", "");
+            printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                    memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+                    nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
+                    nativeFree+dalvikFree);
 
             pw.println(" ");
             pw.println(" Objects");
@@ -916,6 +929,13 @@
                 pw.println(" Asset Allocations");
                 pw.print(assetAlloc);
             }
+
+            return memInfo;
+        }
+
+        @Override
+        public void dumpGfxInfo(FileDescriptor fd, String[] args) {
+            dumpGraphicsInfo(fd);
         }
 
         private void printRow(PrintWriter pw, String format, Object...objs) {
@@ -3538,6 +3558,7 @@
     }
 
     final void handleTrimMemory(int level) {
+        WindowManagerImpl.getDefault().trimMemory(level);
     }
 
     private final void handleBindApplication(AppBindData data) {
@@ -4051,7 +4072,7 @@
         sThreadLocal.set(this);
         mSystemThread = system;
         if (!system) {
-            ViewAncestor.addFirstDrawHandler(new Runnable() {
+            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                 public void run() {
                     ensureJitEnabled();
                 }
@@ -4081,7 +4102,7 @@
             }
         }
         
-        ViewAncestor.addConfigCallback(new ComponentCallbacks() {
+        ViewRootImpl.addConfigCallback(new ComponentCallbacks() {
             public void onConfigurationChanged(Configuration newConfig) {
                 synchronized (mPackages) {
                     // We need to apply this change to the resources
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 16181e0..942f245 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -485,6 +485,48 @@
             scheduleTrimMemory(level);
             return true;
         }
+
+        case DUMP_MEM_INFO_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            ParcelFileDescriptor fd = data.readFileDescriptor();
+            String[] args = data.readStringArray();
+            Debug.MemoryInfo mi = null;
+            if (fd != null) {
+                try {
+                    mi = dumpMemInfo(fd.getFileDescriptor(), args);
+                } finally {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                        // swallowed, not propagated back to the caller
+                    }
+                }
+            }
+            reply.writeNoException();
+            mi.writeToParcel(reply, 0);
+            return true;
+        }
+
+        case DUMP_GFX_INFO_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            ParcelFileDescriptor fd = data.readFileDescriptor();
+            String[] args = data.readStringArray();
+            if (fd != null) {
+                try {
+                    dumpGfxInfo(fd.getFileDescriptor(), args);
+                } finally {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                        // swallowed, not propagated back to the caller
+                    }
+                }
+            }
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -1004,4 +1046,28 @@
         mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
     }
+
+    public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeFileDescriptor(fd);
+        data.writeStringArray(args);
+        mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
+        reply.readException();
+        Debug.MemoryInfo info = new Debug.MemoryInfo();
+        info.readFromParcel(reply);
+        data.recycle();
+        reply.recycle();
+        return info;
+    }
+
+    public void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeFileDescriptor(fd);
+        data.writeStringArray(args);
+        mRemote.transact(DUMP_GFX_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 285f1c1..c82c9ec 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1307,6 +1307,7 @@
             mExecutingActions = true;
             for (int i=0; i<numActions; i++) {
                 mTmpActions[i].run();
+                mTmpActions[i] = null;
             }
             mExecutingActions = false;
             didSomething = true;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 94c2c86..9de0bf4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -120,6 +120,8 @@
     void setCoreSettings(Bundle coreSettings) throws RemoteException;
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
     void scheduleTrimMemory(int level) throws RemoteException;
+    Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException;
+    void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -164,4 +166,6 @@
     int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
     int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
     int SCHEDULE_TRIM_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
+    int DUMP_MEM_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
+    int DUMP_GFX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 7fd5a7d..8472b31 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -40,7 +40,7 @@
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -592,7 +592,7 @@
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -630,7 +630,7 @@
             int x, int y, int z, Bundle extras) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+            ViewRootImpl.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
                     windowToken, action, x, y, z, extras, false);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -650,7 +650,7 @@
      */
     public void clearWallpaperOffsets(IBinder windowToken) {
         try {
-            ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, -1, -1, -1, -1);
         } catch (RemoteException e) {
             // Ignore.
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index a2af558..0e83dc0 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -20,17 +20,21 @@
 import android.database.IContentObserver;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.util.SparseIntArray;
 import android.Manifest;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -70,6 +74,40 @@
             } else {
                 mSyncManager.dump(fd, pw);
             }
+            pw.println();
+            pw.println("Observer tree:");
+            synchronized (mRootNode) {
+                int[] counts = new int[2];
+                final SparseIntArray pidCounts = new SparseIntArray();
+                mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
+                pw.println();
+                ArrayList<Integer> sorted = new ArrayList<Integer>();
+                for (int i=0; i<pidCounts.size(); i++) {
+                    sorted.add(pidCounts.keyAt(i));
+                }
+                Collections.sort(sorted, new Comparator<Integer>() {
+                    @Override
+                    public int compare(Integer lhs, Integer rhs) {
+                        int lc = pidCounts.get(lhs);
+                        int rc = pidCounts.get(rhs);
+                        if (lc < rc) {
+                            return 1;
+                        } else if (lc > rc) {
+                            return -1;
+                        }
+                        return 0;
+                    }
+
+                });
+                for (int i=0; i<sorted.size(); i++) {
+                    int pid = sorted.get(i);
+                    pw.print("  pid "); pw.print(pid); pw.print(": ");
+                            pw.print(pidCounts.get(pid)); pw.println(" observers");
+                }
+                pw.println();
+                pw.print(" Total number of nodes: "); pw.println(counts[0]);
+                pw.print(" Total number of observers: "); pw.println(counts[1]);
+            }
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -102,7 +140,8 @@
             throw new IllegalArgumentException("You must pass a valid uri and observer");
         }
         synchronized (mRootNode) {
-            mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode);
+            mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode,
+                    Binder.getCallingUid(), Binder.getCallingPid());
             if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
                     " with notifyForDescendents " + notifyForDescendents);
         }
@@ -465,12 +504,17 @@
     public static final class ObserverNode {
         private class ObserverEntry implements IBinder.DeathRecipient {
             public final IContentObserver observer;
+            public final int uid;
+            public final int pid;
             public final boolean notifyForDescendents;
             private final Object observersLock;
 
-            public ObserverEntry(IContentObserver o, boolean n, Object observersLock) {
+            public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
+                    int _uid, int _pid) {
                 this.observersLock = observersLock;
                 observer = o;
+                uid = _uid;
+                pid = _pid;
                 notifyForDescendents = n;
                 try {
                     observer.asBinder().linkToDeath(this, 0);
@@ -484,6 +528,16 @@
                     removeObserverLocked(observer);
                 }
             }
+
+            public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+                    String name, String prefix, SparseIntArray pidCounts) {
+                pidCounts.put(pid, pidCounts.get(pid)+1);
+                pw.print(prefix); pw.print(name); pw.print(": pid=");
+                        pw.print(pid); pw.print(" uid=");
+                        pw.print(uid); pw.print(" target=");
+                        pw.println(Integer.toHexString(System.identityHashCode(
+                                observer != null ? observer.asBinder() : null)));
+            }
         }
 
         public static final int INSERT_TYPE = 0;
@@ -498,6 +552,37 @@
             mName = name;
         }
 
+        public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+                String name, String prefix, int[] counts, SparseIntArray pidCounts) {
+            String innerName = null;
+            if (mObservers.size() > 0) {
+                if ("".equals(name)) {
+                    innerName = mName;
+                } else {
+                    innerName = name + "/" + mName;
+                }
+                for (int i=0; i<mObservers.size(); i++) {
+                    counts[1]++;
+                    mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
+                            pidCounts);
+                }
+            }
+            if (mChildren.size() > 0) {
+                if (innerName == null) {
+                    if ("".equals(name)) {
+                        innerName = mName;
+                    } else {
+                        innerName = name + "/" + mName;
+                    }
+                }
+                for (int i=0; i<mChildren.size(); i++) {
+                    counts[0]++;
+                    mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
+                            counts, pidCounts);
+                }
+            }
+        }
+
         private String getUriSegment(Uri uri, int index) {
             if (uri != null) {
                 if (index == 0) {
@@ -518,15 +603,16 @@
         }
 
         public void addObserverLocked(Uri uri, IContentObserver observer,
-                boolean notifyForDescendents, Object observersLock) {
-            addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock);
+                boolean notifyForDescendents, Object observersLock, int uid, int pid) {
+            addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid);
         }
 
         private void addObserverLocked(Uri uri, int index, IContentObserver observer,
-                boolean notifyForDescendents, Object observersLock) {
+                boolean notifyForDescendents, Object observersLock, int uid, int pid) {
             // If this is the leaf node add the observer
             if (index == countUriSegments(uri)) {
-                mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock));
+                mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock,
+                        uid, pid));
                 return;
             }
 
@@ -539,7 +625,8 @@
             for (int i = 0; i < N; i++) {
                 ObserverNode node = mChildren.get(i);
                 if (node.mName.equals(segment)) {
-                    node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
+                    node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
+                            observersLock, uid, pid);
                     return;
                 }
             }
@@ -547,7 +634,8 @@
             // No child found, create one
             ObserverNode node = new ObserverNode(segment);
             mChildren.add(node);
-            node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
+            node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
+                    observersLock, uid, pid);
         }
 
         public boolean removeObserverLocked(IContentObserver observer) {
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/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index ccef122..aa6400bb 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -19,6 +19,7 @@
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 
 import android.content.Context;
+import android.os.Build;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.util.Objects;
@@ -68,7 +69,7 @@
             subTypeName = Integer.toString(mSubType);
         }
 
-        final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+        final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
         final String roaming = mRoaming ? ", ROAMING" : "";
         return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId="
                 + scrubSubscriberId + roaming + "]";
@@ -91,6 +92,17 @@
     }
 
     /**
+     * Scrub given IMSI on production builds.
+     */
+    public static String scrubSubscriberId(String subscriberId) {
+        if ("eng".equals(Build.TYPE)) {
+            return subscriberId;
+        } else {
+            return subscriberId != null ? "valid" : "null";
+        }
+    }
+
+    /**
      * Build a {@link NetworkIdentity} from the given {@link NetworkState},
      * assuming that any mobile networks are using the current IMSI.
      */
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 1ef0d9d..cd49023 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -16,10 +16,11 @@
 
 package android.net;
 
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkIdentity.scrubSubscriberId;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
@@ -119,7 +120,7 @@
 
     @Override
     public String toString() {
-        final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+        final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
         return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId="
                 + scrubSubscriberId;
     }
@@ -150,7 +151,7 @@
     }
 
     /**
-     * Test if this network matches the given template and IMEI.
+     * Test if this network matches the given template and IMSI.
      */
     public boolean matches(NetworkIdentity ident) {
         switch (mMatchRule) {
@@ -170,7 +171,7 @@
     }
 
     /**
-     * Check if mobile network with matching IMEI. Also matches
+     * Check if mobile network with matching IMSI. Also matches
      * {@link #TYPE_WIMAX}.
      */
     private boolean matchesMobile(NetworkIdentity ident) {
@@ -183,7 +184,7 @@
     }
 
     /**
-     * Check if mobile network classified 3G or lower with matching IMEI.
+     * Check if mobile network classified 3G or lower with matching IMSI.
      */
     private boolean matchesMobile3gLower(NetworkIdentity ident) {
         if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
@@ -198,7 +199,7 @@
     }
 
     /**
-     * Check if mobile network classified 4G with matching IMEI. Also matches
+     * Check if mobile network classified 4G with matching IMSI. Also matches
      * {@link #TYPE_WIMAX}.
      */
     private boolean matchesMobile4g(NetworkIdentity ident) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ba69246..da2afb6 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -129,6 +129,11 @@
         /** The shared dirty pages used by everything else. */
         public int otherSharedDirty;
 
+        /** @hide */
+        public static final int NUM_OTHER_STATS = 9;
+
+        private int[] otherStats = new int[NUM_OTHER_STATS*3];
+
         public MemoryInfo() {
         }
 
@@ -153,6 +158,38 @@
             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
         }
 
+        /* @hide */
+        public int getOtherPss(int which) {
+            return otherStats[which*3];
+        }
+
+        /* @hide */
+        public int getOtherPrivateDirty(int which) {
+            return otherStats[which*3 + 1];
+        }
+
+        /* @hide */
+        public int getOtherSharedDirty(int which) {
+            return otherStats[which*3 + 2];
+        }
+
+
+        /* @hide */
+        public static String getOtherLabel(int which) {
+            switch (which) {
+                case 0: return "Cursor";
+                case 1: return "Ashmem";
+                case 2: return "Other dev";
+                case 3: return ".so mmap";
+                case 4: return ".jar mmap";
+                case 5: return ".apk mmap";
+                case 6: return ".ttf mmap";
+                case 7: return ".dex mmap";
+                case 8: return "Other mmap";
+                default: return "????";
+            }
+        }
+
         public int describeContents() {
             return 0;
         }
@@ -167,6 +204,7 @@
             dest.writeInt(otherPss);
             dest.writeInt(otherPrivateDirty);
             dest.writeInt(otherSharedDirty);
+            dest.writeIntArray(otherStats);
         }
 
         public void readFromParcel(Parcel source) {
@@ -179,6 +217,7 @@
             otherPss = source.readInt();
             otherPrivateDirty = source.readInt();
             otherSharedDirty = source.readInt();
+            otherStats = source.createIntArray();
         }
 
         public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
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/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 8fc8b9d..c51ba2a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -51,7 +51,7 @@
 import android.view.SurfaceHolder;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
@@ -650,7 +650,7 @@
             mWindowToken = wrapper.mWindowToken;
             mSurfaceHolder.setSizeFromLayout();
             mInitializing = true;
-            mSession = ViewAncestor.getWindowSession(getMainLooper());
+            mSession = ViewRootImpl.getWindowSession(getMainLooper());
             
             mWindow.setSession(mSession);
             
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index dea708a..96864c4 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -17,6 +17,7 @@
 
 import android.media.AudioFormat;
 import android.media.AudioTrack;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.Iterator;
@@ -25,6 +26,7 @@
 
 class AudioPlaybackHandler {
     private static final String TAG = "TTS.AudioPlaybackHandler";
+    private static final boolean DBG_THREADING = false;
     private static final boolean DBG = false;
 
     private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
@@ -64,70 +66,105 @@
      * Stops all synthesis for a given {@code token}. If the current token
      * is currently being processed, an effort will be made to stop it but
      * that is not guaranteed.
+     *
+     * NOTE: This assumes that all other messages in the queue with {@code token}
+     * have been removed already.
+     *
+     * NOTE: Must be called synchronized on {@code AudioPlaybackHandler.this}.
      */
-    synchronized public void stop(MessageParams token) {
+    private void stop(MessageParams token) {
         if (token == null) {
             return;
         }
 
-        removeMessages(token);
+        if (DBG) Log.d(TAG, "Stopping token : " + token);
 
         if (token.getType() == MessageParams.TYPE_SYNTHESIS) {
             AudioTrack current = ((SynthesisMessageParams) token).getAudioTrack();
             if (current != null) {
                 // Stop the current audio track if it's still playing.
-                // The audio track is thread safe in this regard.
+                // The audio track is thread safe in this regard. The current
+                // handleSynthesisDataAvailable call will return soon after this
+                // call.
                 current.stop();
             }
+            // This is safe because PlaybackSynthesisCallback#stop would have
+            // been called before this method, and will no longer enqueue any
+            // audio for this token.
+            //
+            // (Even if it did, all it would result in is a warning message).
             mQueue.add(new ListEntry(SYNTHESIS_DONE, token, HIGH_PRIORITY));
-        } else  {
-            final MessageParams current = getCurrentParams();
-
-            if (current != null) {
-                if (token.getType() == MessageParams.TYPE_AUDIO) {
-                    ((AudioMessageParams) current).getPlayer().stop();
-                } else if (token.getType() == MessageParams.TYPE_SILENCE) {
-                    ((SilenceMessageParams) current).getConditionVariable().open();
-                }
-            }
+        } else if (token.getType() == MessageParams.TYPE_AUDIO) {
+            ((AudioMessageParams) token).getPlayer().stop();
+            // No cleanup required for audio messages.
+        } else if (token.getType() == MessageParams.TYPE_SILENCE) {
+            ((SilenceMessageParams) token).getConditionVariable().open();
+            // No cleanup required for silence messages.
         }
     }
 
+    // -----------------------------------------------------
+    // Methods that add and remove elements from the queue. These do not
+    // need to be synchronized strictly speaking, but they make the behaviour
+    // a lot more predictable. (though it would still be correct without
+    // synchronization).
+    // -----------------------------------------------------
+
     synchronized public void removePlaybackItems(String callingApp) {
+        if (DBG_THREADING) Log.d(TAG, "Removing all callback items for : " + callingApp);
         removeMessages(callingApp);
-        stop(getCurrentParams());
+
+        final MessageParams current = getCurrentParams();
+        if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
+            stop(current);
+        }
     }
 
     synchronized public void removeAllItems() {
+        if (DBG_THREADING) Log.d(TAG, "Removing all items");
         removeAllMessages();
         stop(getCurrentParams());
     }
 
     /**
+     * @return false iff the queue is empty and no queue item is currently
+     *        being handled, true otherwise.
+     */
+    public boolean isSpeaking() {
+        return (mQueue.peek() != null) || (mCurrentParams != null);
+    }
+
+    /**
      * Shut down the audio playback thread.
      */
     synchronized public void quit() {
+        removeAllMessages();
         stop(getCurrentParams());
         mQueue.add(new ListEntry(SHUTDOWN, null, HIGH_PRIORITY));
     }
 
-    void enqueueSynthesisStart(SynthesisMessageParams token) {
+    synchronized void enqueueSynthesisStart(SynthesisMessageParams token) {
+        if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis start : " + token);
         mQueue.add(new ListEntry(SYNTHESIS_START, token));
     }
 
-    void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+    synchronized void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+        if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis data available : " + token);
         mQueue.add(new ListEntry(SYNTHESIS_DATA_AVAILABLE, token));
     }
 
-    void enqueueSynthesisDone(SynthesisMessageParams token) {
+    synchronized void enqueueSynthesisDone(SynthesisMessageParams token) {
+        if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis done : " + token);
         mQueue.add(new ListEntry(SYNTHESIS_DONE, token));
     }
 
-    void enqueueAudio(AudioMessageParams token) {
+    synchronized void enqueueAudio(AudioMessageParams token) {
+        if (DBG_THREADING) Log.d(TAG, "Enqueuing audio : " + token);
         mQueue.add(new ListEntry(PLAY_AUDIO, token));
     }
 
-    void enqueueSilence(SilenceMessageParams token) {
+    synchronized void enqueueSilence(SilenceMessageParams token) {
+        if (DBG_THREADING) Log.d(TAG, "Enqueuing silence : " + token);
         mQueue.add(new ListEntry(PLAY_SILENCE, token));
     }
 
@@ -172,26 +209,6 @@
     }
 
     /*
-     * Remove all messages from the queue that contain the supplied token.
-     * Note that the Iterator is thread safe, and other methods can safely
-     * continue adding to the queue at this point.
-     */
-    synchronized private void removeMessages(MessageParams token) {
-        if (token == null) {
-            return;
-        }
-
-        Iterator<ListEntry> it = mQueue.iterator();
-
-        while (it.hasNext()) {
-            final ListEntry current = it.next();
-            if (current.mMessage == token) {
-                it.remove();
-            }
-        }
-    }
-
-    /*
      * Atomically clear the queue of all messages.
      */
     synchronized private void removeAllMessages() {
@@ -255,6 +272,13 @@
     }
 
     private void setCurrentParams(MessageParams p) {
+        if (DBG_THREADING) {
+            if (p != null) {
+                Log.d(TAG, "Started handling :" + p);
+            } else {
+                Log.d(TAG, "End handling : " + mCurrentParams);
+            }
+        }
         mCurrentParams = p;
     }
 
@@ -345,7 +369,7 @@
     private void handleSynthesisDataAvailable(MessageParams msg) {
         final SynthesisMessageParams param = (SynthesisMessageParams) msg;
         if (param.getAudioTrack() == null) {
-            Log.w(TAG, "Error : null audio track in handleDataAvailable.");
+            Log.w(TAG, "Error : null audio track in handleDataAvailable : " + param);
             return;
         }
 
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
index 4c1b6d2..e7d6da3 100644
--- a/core/java/android/speech/tts/MessageParams.java
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -38,5 +38,10 @@
         return mCallingApp;
     }
 
+    @Override
+    public String toString() {
+        return "MessageParams[" + hashCode() + "]";
+    }
+
     abstract int getType();
 }
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 04bd745..7dbf1ac 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -90,12 +90,10 @@
                 Log.w(TAG, "stop() called twice");
                 return;
             }
+
             // mToken will be null if the engine encounters
             // an error before it called start().
-            if (mToken != null) {
-                mAudioTrackHandler.stop(mToken);
-                mToken = null;
-            } else {
+            if (mToken == null) {
                 // In all other cases, mAudioTrackHandler.stop() will
                 // result in onComplete being called.
                 mLogger.onWriteData();
@@ -158,7 +156,7 @@
         }
 
         synchronized (mStateLock) {
-            if (mToken == null) {
+            if (mToken == null || mStopped) {
                 return TextToSpeech.ERROR;
             }
 
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 32ca226..5126e48 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -109,6 +109,11 @@
     /**
      * Broadcast Action: The TextToSpeech synthesizer has completed processing
      * of all the text in the speech queue.
+     *
+     * Note that this notifies callers when the <b>engine</b> has finished has
+     * processing text data. Audio playback might not have completed (or even started)
+     * at this point. If you wish to be notified when this happens, see
+     * {@link OnUtteranceCompletedListener}.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
@@ -576,6 +581,14 @@
                 service.setCallback(getPackageName(), null);
                 service.stop(getPackageName());
                 mServiceConnection.disconnect();
+                // Context#unbindService does not result in a call to
+                // ServiceConnection#onServiceDisconnected. As a result, the
+                // service ends up being destroyed (if there are no other open
+                // connections to it) but the process lives on and the
+                // ServiceConnection continues to refer to the destroyed service.
+                //
+                // This leads to tons of log spam about SynthThread being dead.
+                mServiceConnection = null;
                 mCurrentEngine = null;
                 return null;
             }
@@ -796,7 +809,10 @@
     }
 
     /**
-     * Checks whether the TTS engine is busy speaking.
+     * Checks whether the TTS engine is busy speaking. Note that a speech item is
+     * considered complete once it's audio data has been sent to the audio mixer, or
+     * written to a file. There might be a finite lag between this point, and when
+     * the audio hardware completes playback.
      *
      * @return {@code true} if the TTS engine is speaking.
      */
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 010c155..1926c92 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -282,6 +282,8 @@
             if (current != null) {
                 current.stop();
             }
+
+            // The AudioPlaybackHandler will be destroyed by the caller.
         }
 
         /**
@@ -337,6 +339,8 @@
             }
 
             removeCallbacksAndMessages(callingApp);
+            // This stops writing data to the file / or publishing
+            // items to the audio playback handler.
             SpeechItem current = setCurrentSpeechItem(null);
             if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
                 current.stop();
@@ -628,9 +632,7 @@
 
         @Override
         protected void stopImpl() {
-            if (mToken != null) {
-                mAudioPlaybackHandler.stop(mToken);
-            }
+            // Do nothing.
         }
     }
 
@@ -657,9 +659,7 @@
 
         @Override
         protected void stopImpl() {
-            if (mToken != null) {
-                mAudioPlaybackHandler.stop(mToken);
-            }
+            // Do nothing.
         }
     }
 
@@ -719,7 +719,7 @@
         }
 
         public boolean isSpeaking() {
-            return mSynthHandler.isSpeaking();
+            return mSynthHandler.isSpeaking() || mAudioPlaybackHandler.isSpeaking();
         }
 
         public int stop(String callingApp) {
@@ -767,10 +767,6 @@
             mCallbacks.setCallback(packageName, cb);
         }
 
-        private boolean isDefault(String lang, String country, String variant) {
-            return Locale.getDefault().equals(new Locale(lang, country, variant));
-        }
-
         private String intern(String in) {
             // The input parameter will be non null.
             return in.intern();
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/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 4987e2f..80244bb 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -286,6 +286,38 @@
 
     private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
 
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Memory
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @see #flushCaches(int) 
+     */
+    public static final int FLUSH_CACHES_MODERATE = 0;
+
+    /**
+     * @see #flushCaches(int) 
+     */
+    public static final int FLUSH_CACHES_FULL = 1;
+
+    /**
+     * Flush caches to reclaim as much memory as possible. The amount of memory
+     * to reclaim is indicate by the level parameter.
+     * 
+     * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
+     * {@link #FLUSH_CACHES_FULL}.
+     * 
+     * @param level Hint about the amount of memory to reclaim
+     * 
+     * @hide
+     */
+    public static void flushCaches(int level) {
+        nFlushCaches(level);
+    }
+
+    private static native void nFlushCaches(int level);
+
     ///////////////////////////////////////////////////////////////////////////
     // Display list
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 011e44c..9a2564f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.content.ComponentCallbacks;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -263,6 +264,18 @@
     }
 
     /**
+     * Invoke this method when the system is running out of memory. This
+     * method will attempt to recover as much memory as possible, based on
+     * the specified hint.
+     * 
+     * @param level Hint about the amount of memory that should be trimmed,
+     *              see {@link android.content.ComponentCallbacks}
+     */
+    static void trimMemory(int level) {
+        Gl20Renderer.flushCaches(level);
+    }
+
+    /**
      * Indicates whether hardware acceleration is currently enabled.
      * 
      * @return True if hardware acceleration is in use, false otherwise.
@@ -858,5 +871,16 @@
             }
             return null;
         }
+        
+        static void flushCaches(int level) {
+            switch (level) {
+                case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
+                    break;
+                case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
+                    break;
+            }
+        }
     }
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 764899f..cbdb38e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -426,7 +426,7 @@
         if (!mHaveFrame) {
             return;
         }
-        ViewAncestor viewRoot = (ViewAncestor) getRootView().getParent();
+        ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent();
         if (viewRoot != null) {
             mTranslator = viewRoot.mTranslator;
         }
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 2a65f0c..4e9c0b7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5043,9 +5043,9 @@
     }
 
     /** Gets the ViewAncestor, or null if not attached. */
-    /*package*/ ViewAncestor getViewAncestor() {
+    /*package*/ ViewRootImpl getViewRootImpl() {
         View root = getRootView();
-        return root != null ? (ViewAncestor)root.getParent() : null;
+        return root != null ? (ViewRootImpl)root.getParent() : null;
     }
 
     /**
@@ -5061,7 +5061,7 @@
     public final boolean requestFocusFromTouch() {
         // Leave touch mode if we need to
         if (isInTouchMode()) {
-            ViewAncestor viewRoot = getViewAncestor();
+            ViewRootImpl viewRoot = getViewRootImpl();
             if (viewRoot != null) {
                 viewRoot.ensureTouchMode(false);
             }
@@ -5653,7 +5653,7 @@
         if (mAttachInfo != null) {
             return mAttachInfo.mInTouchMode;
         } else {
-            return ViewAncestor.isInTouchMode();
+            return ViewRootImpl.isInTouchMode();
         }
     }
 
@@ -8254,7 +8254,7 @@
             handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
-            ViewAncestor.getRunQueue().post(action);
+            ViewRootImpl.getRunQueue().post(action);
             return true;
         }
 
@@ -8284,7 +8284,7 @@
             handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
-            ViewAncestor.getRunQueue().postDelayed(action, delayMillis);
+            ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
             return true;
         }
 
@@ -8308,7 +8308,7 @@
             handler = attachInfo.mHandler;
         } else {
             // Assume that post will succeed later
-            ViewAncestor.getRunQueue().removeCallbacks(action);
+            ViewRootImpl.getRunQueue().removeCallbacks(action);
             return true;
         }
 
@@ -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;
@@ -11122,6 +11122,10 @@
      *        background
      */
     public void setBackgroundDrawable(Drawable d) {
+        if (d == mBGDrawable) {
+            return;
+        }
+
         boolean requestLayout = false;
 
         mBackgroundResource = 0;
@@ -11576,9 +11580,9 @@
             viewParent = view.mParent;
         }
 
-        if (viewParent instanceof ViewAncestor) {
+        if (viewParent instanceof ViewRootImpl) {
             // *cough*
-            final ViewAncestor vr = (ViewAncestor)viewParent;
+            final ViewRootImpl vr = (ViewRootImpl)viewParent;
             location[1] -= vr.mCurScrollY;
         }
     }
@@ -12705,7 +12709,7 @@
                     surface.unlockCanvasAndPost(canvas);
                 }
 
-                final ViewAncestor root = getViewAncestor();
+                final ViewRootImpl root = getViewRootImpl();
 
                 // Cache the local state object for delivery with DragEvents
                 root.setLocalDragState(myLocalState);
@@ -13912,7 +13916,7 @@
         Canvas mCanvas;
 
         /**
-         * A Handler supplied by a view's {@link android.view.ViewAncestor}. This
+         * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
          * handler can be used to pump events in the UI events queue.
          */
         final Handler mHandler;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index f7f5a21..b85159b 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -366,7 +366,7 @@
     }
 
     private static BufferedWriter sHierarchyTraces;
-    private static ViewAncestor sHierarhcyRoot;
+    private static ViewRootImpl sHierarhcyRoot;
     private static String sHierarchyTracePrefix;
 
     /**
@@ -415,7 +415,7 @@
      * @hide
      */
     public static long getViewAncestorInstanceCount() {
-        return Debug.countInstancesOfClass(ViewAncestor.class);
+        return Debug.countInstancesOfClass(ViewRootImpl.class);
     }
 
     /**
@@ -748,7 +748,7 @@
             return;
         }
 
-        sHierarhcyRoot = (ViewAncestor) view.getRootView().getParent();
+        sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent();
     }
 
     /**
@@ -1100,7 +1100,7 @@
 
     private static void outputDisplayList(View root, String parameter) throws IOException {
         final View view = findView(root, parameter);
-        view.getViewAncestor().outputDisplayList(view);
+        view.getViewRootImpl().outputDisplayList(view);
     }
 
     private static void capture(View root, final OutputStream clientStream, String parameter)
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cb3e9c6..5f7673a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -954,7 +954,7 @@
         final float tx = event.mX;
         final float ty = event.mY;
 
-        ViewAncestor root = getViewAncestor();
+        ViewRootImpl root = getViewRootImpl();
 
         // Dispatch down the view hierarchy
         switch (event.mAction) {
@@ -3839,13 +3839,13 @@
                     if (drawAnimation) {
                         if (view != null) {
                             view.mPrivateFlags |= DRAW_ANIMATION;
-                        } else if (parent instanceof ViewAncestor) {
-                            ((ViewAncestor) parent).mIsAnimating = true;
+                        } else if (parent instanceof ViewRootImpl) {
+                            ((ViewRootImpl) parent).mIsAnimating = true;
                         }
                     }
 
-                    if (parent instanceof ViewAncestor) {
-                        ((ViewAncestor) parent).invalidate();
+                    if (parent instanceof ViewRootImpl) {
+                        ((ViewRootImpl) parent).invalidate();
                         parent = null;
                     } else if (view != null) {
                         if ((view.mPrivateFlags & DRAWN) == DRAWN ||
@@ -3902,8 +3902,8 @@
                     if (drawAnimation) {
                         if (view != null) {
                             view.mPrivateFlags |= DRAW_ANIMATION;
-                        } else if (parent instanceof ViewAncestor) {
-                            ((ViewAncestor) parent).mIsAnimating = true;
+                        } else if (parent instanceof ViewRootImpl) {
+                            ((ViewRootImpl) parent).mIsAnimating = true;
                         }
                     }
 
@@ -4426,7 +4426,7 @@
             // If this group is dirty, check that the parent is dirty as well
             if ((mPrivateFlags & DIRTY_MASK) != 0) {
                 final ViewParent parent = getParent();
-                if (parent != null && !(parent instanceof ViewAncestor)) {
+                if (parent != null && !(parent instanceof ViewRootImpl)) {
                     if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
                         result = false;
                         android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
@@ -4995,7 +4995,7 @@
      * @hide
      */
     public void requestTransitionStart(LayoutTransition transition) {
-        ViewAncestor viewAncestor = getViewAncestor();
+        ViewRootImpl viewAncestor = getViewRootImpl();
         viewAncestor.requestTransitionStart(transition);
     }
 
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewRootImpl.java
similarity index 98%
rename from core/java/android/view/ViewAncestor.java
rename to core/java/android/view/ViewRootImpl.java
index ac73611..470493d 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -92,7 +92,7 @@
  * {@hide}
  */
 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewAncestor extends Handler implements ViewParent,
+public final class ViewRootImpl extends Handler implements ViewParent,
         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
     private static final String TAG = "ViewAncestor";
     private static final boolean DBG = false;
@@ -303,7 +303,7 @@
         }
     }
     
-    public ViewAncestor(Context context) {
+    public ViewRootImpl(Context context) {
         super();
 
         if (MEASURE_LATENCY) {
@@ -3807,14 +3807,14 @@
     }
     
     static class InputMethodCallback extends IInputMethodCallback.Stub {
-        private WeakReference<ViewAncestor> mViewAncestor;
+        private WeakReference<ViewRootImpl> mViewAncestor;
 
-        public InputMethodCallback(ViewAncestor viewAncestor) {
-            mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+        public InputMethodCallback(ViewRootImpl viewAncestor) {
+            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
         }
 
         public void finishedEvent(int seq, boolean handled) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchFinishedEvent(seq, handled);
             }
@@ -3826,15 +3826,15 @@
     }
 
     static class W extends IWindow.Stub {
-        private final WeakReference<ViewAncestor> mViewAncestor;
+        private final WeakReference<ViewRootImpl> mViewAncestor;
 
-        W(ViewAncestor viewAncestor) {
-            mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+        W(ViewRootImpl viewAncestor) {
+            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
         }
 
         public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
                 boolean reportDraw, Configuration newConfig) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw,
                         newConfig);
@@ -3842,21 +3842,21 @@
         }
 
         public void dispatchAppVisibility(boolean visible) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchAppVisibility(visible);
             }
         }
 
         public void dispatchGetNewSurface() {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchGetNewSurface();
             }
         }
 
         public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.windowFocusChanged(hasFocus, inTouchMode);
             }
@@ -3872,7 +3872,7 @@
         }
 
         public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 final View view = viewAncestor.mView;
                 if (view != null) {
@@ -3903,7 +3903,7 @@
         }
         
         public void closeSystemDialogs(String reason) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchCloseSystemDialogs(reason);
             }
@@ -3931,14 +3931,14 @@
 
         /* Drag/drop */
         public void dispatchDragEvent(DragEvent event) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchDragEvent(event);
             }
         }
 
         public void dispatchSystemUiVisibilityChanged(int visibility) {
-            final ViewAncestor viewAncestor = mViewAncestor.get();
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchSystemUiVisibilityChanged(visibility);
             }
@@ -4269,7 +4269,7 @@
             if (!registered) {
                 mAttachInfo.mAccessibilityWindowId =
                     mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
-                            new AccessibilityInteractionConnection(ViewAncestor.this));
+                            new AccessibilityInteractionConnection(ViewRootImpl.this));
             }
         }
 
@@ -4289,10 +4289,10 @@
      */
     final class AccessibilityInteractionConnection
             extends IAccessibilityInteractionConnection.Stub {
-        private final WeakReference<ViewAncestor> mViewAncestor;
+        private final WeakReference<ViewRootImpl> mViewAncestor;
 
-        AccessibilityInteractionConnection(ViewAncestor viewAncestor) {
-            mViewAncestor = new WeakReference<ViewAncestor>(viewAncestor);
+        AccessibilityInteractionConnection(ViewRootImpl viewAncestor) {
+            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
         }
 
         public void findAccessibilityNodeInfoByAccessibilityId(int accessibilityId,
@@ -4421,7 +4421,7 @@
             try {
                 FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate;
                 predicate.init(accessibilityId);
-                View root = ViewAncestor.this.mView;
+                View root = ViewRootImpl.this.mView;
                 View target = root.findViewByPredicate(predicate);
                 if (target != null && target.isShown()) {
                     info = target.createAccessibilityNodeInfo();
@@ -4453,7 +4453,7 @@
 
             AccessibilityNodeInfo info = null;
             try {
-                View root = ViewAncestor.this.mView;
+                View root = ViewRootImpl.this.mView;
                 View target = root.findViewById(viewId);
                 if (target != null && target.isShown()) {
                     info = target.createAccessibilityNodeInfo();
@@ -4499,7 +4499,7 @@
                 if (accessibilityViewId != View.NO_ID) {
                     root = findViewByAccessibilityId(accessibilityViewId);
                 } else {
-                    root = ViewAncestor.this.mView;
+                    root = ViewRootImpl.this.mView;
                 }
 
                 if (root == null || !root.isShown()) {
@@ -4624,7 +4624,7 @@
         }
 
         private View findViewByAccessibilityId(int accessibilityId) {
-            View root = ViewAncestor.this.mView;
+            View root = ViewRootImpl.this.mView;
             if (root == null) {
                 return null;
             }
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 54e7c04..a451bb5 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,18 +16,16 @@
 
 package android.view;
 
-import java.util.HashMap;
-
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
-import android.util.Slog;
-import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 
+import java.util.HashMap;
+
 final class WindowLeaked extends AndroidRuntimeException {
     public WindowLeaked(String msg) {
         super(msg);
@@ -80,7 +78,7 @@
     public static final int ADD_PERMISSION_DENIED = -8;
 
     private View[] mViews;
-    private ViewAncestor[] mRoots;
+    private ViewRootImpl[] mRoots;
     private WindowManager.LayoutParams[] mParams;
 
     private final static Object sLock = new Object();
@@ -204,7 +202,7 @@
         final WindowManager.LayoutParams wparams
                 = (WindowManager.LayoutParams)params;
         
-        ViewAncestor root;
+        ViewRootImpl root;
         View panelParentView = null;
         
         synchronized (this) {
@@ -241,7 +239,7 @@
                 }
             }
             
-            root = new ViewAncestor(view.getContext());
+            root = new ViewRootImpl(view.getContext());
             root.mAddNesting = 1;
             if (cih == null) {
                 root.mCompatibilityInfo = new CompatibilityInfoHolder();
@@ -254,7 +252,7 @@
             if (mViews == null) {
                 index = 1;
                 mViews = new View[1];
-                mRoots = new ViewAncestor[1];
+                mRoots = new ViewRootImpl[1];
                 mParams = new WindowManager.LayoutParams[1];
             } else {
                 index = mViews.length + 1;
@@ -262,7 +260,7 @@
                 mViews = new View[index];
                 System.arraycopy(old, 0, mViews, 0, index-1);
                 old = mRoots;
-                mRoots = new ViewAncestor[index];
+                mRoots = new ViewRootImpl[index];
                 System.arraycopy(old, 0, mRoots, 0, index-1);
                 old = mParams;
                 mParams = new WindowManager.LayoutParams[index];
@@ -290,7 +288,7 @@
 
         synchronized (this) {
             int index = findViewLocked(view, true);
-            ViewAncestor root = mRoots[index];
+            ViewRootImpl root = mRoots[index];
             mParams[index] = wparams;
             root.setLayoutParams(wparams, false);
         }
@@ -312,7 +310,7 @@
     public void removeViewImmediate(View view) {
         synchronized (this) {
             int index = findViewLocked(view, true);
-            ViewAncestor root = mRoots[index];
+            ViewRootImpl root = mRoots[index];
             View curView = root.getView();
             
             root.mAddNesting = 0;
@@ -328,7 +326,7 @@
     }
     
     View removeViewLocked(int index) {
-        ViewAncestor root = mRoots[index];
+        ViewRootImpl root = mRoots[index];
         View view = root.getView();
         
         // Don't really remove until we have matched all calls to add().
@@ -356,7 +354,7 @@
         removeItem(tmpViews, mViews, index);
         mViews = tmpViews;
         
-        ViewAncestor[] tmpRoots = new ViewAncestor[count-1];
+        ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1];
         removeItem(tmpRoots, mRoots, index);
         mRoots = tmpRoots;
         
@@ -383,7 +381,7 @@
                 //Log.i("foo", "@ " + i + " token " + mParams[i].token
                 //        + " view " + mRoots[i].getView());
                 if (token == null || mParams[i].token == token) {
-                    ViewAncestor root = mRoots[i];
+                    ViewRootImpl root = mRoots[i];
                     root.mAddNesting = 1;
                     
                     //Log.i("foo", "Force closing " + root);
@@ -402,7 +400,16 @@
             }
         }
     }
-    
+
+    /**
+     * @param level See {@link android.content.ComponentCallbacks}
+     */
+    public void trimMemory(int level) {
+        if (HardwareRenderer.isAvailable()) {
+            HardwareRenderer.trimMemory(level);
+        }
+    }
+
     public void setStoppedState(IBinder token, boolean stopped) {
         synchronized (this) {
             if (mViews == null)
@@ -410,7 +417,7 @@
             int count = mViews.length;
             for (int i=0; i<count; i++) {
                 if (token == null || mParams[i].token == token) {
-                    ViewAncestor root = mRoots[i];
+                    ViewRootImpl root = mRoots[i];
                     root.setStopped(stopped);
                 }
             }
@@ -422,7 +429,7 @@
             int count = mViews.length;
             config = new Configuration(config);
             for (int i=0; i<count; i++) {
-                ViewAncestor root = mRoots[i];
+                ViewRootImpl root = mRoots[i];
                 root.requestUpdateConfiguration(config);
             }
         }
@@ -430,13 +437,13 @@
 
     public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
         ViewParent vp = view.getParent();
-        while (vp != null && !(vp instanceof ViewAncestor)) {
+        while (vp != null && !(vp instanceof ViewRootImpl)) {
             vp = vp.getParent();
         }
         
         if (vp == null) return null;
         
-        ViewAncestor vr = (ViewAncestor)vp;
+        ViewRootImpl vr = (ViewRootImpl)vp;
         
         int N = mRoots.length;
         for (int i = 0; i < N; ++i) {
@@ -456,8 +463,7 @@
         return new Display(Display.DEFAULT_DISPLAY, null);
     }
 
-    private static void removeItem(Object[] dst, Object[] src, int index)
-    {
+    private static void removeItem(Object[] dst, Object[] src, int index) {
         if (dst.length > 0) {
             if (index > 0) {
                 System.arraycopy(src, 0, dst, 0, index);
@@ -468,8 +474,7 @@
         }
     }
 
-    private int findViewLocked(View view, boolean required)
-    {
+    private int findViewLocked(View view, boolean required) {
         synchronized (this) {
             final int count = mViews != null ? mViews.length : 0;
             for (int i=0; i<count; i++) {
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/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index f4d5e89..210106f 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -50,7 +50,7 @@
  */
 public class AccessibilityRecord {
 
-    private static final int INVALID_POSITION = -1;
+    private static final int UNDEFINED = -1;
 
     private static final int PROPERTY_CHECKED = 0x00000001;
     private static final int PROPERTY_ENABLED = 0x00000002;
@@ -68,15 +68,15 @@
 
     boolean mSealed;
     int mBooleanProperties;
-    int mCurrentItemIndex;
-    int mItemCount;
-    int mFromIndex;
-    int mToIndex;
-    int mScrollX;
-    int mScrollY;
+    int mCurrentItemIndex = UNDEFINED;
+    int mItemCount = UNDEFINED;
+    int mFromIndex = UNDEFINED;
+    int mToIndex = UNDEFINED;
+    int mScrollX = UNDEFINED;
+    int mScrollY = UNDEFINED;
 
-    int mAddedCount;
-    int mRemovedCount;
+    int mAddedCount= UNDEFINED;
+    int mRemovedCount = UNDEFINED;
     int mSourceViewId = View.NO_ID;
     int mSourceWindowId = View.NO_ID;
 
@@ -681,14 +681,14 @@
     void clear() {
         mSealed = false;
         mBooleanProperties = 0;
-        mCurrentItemIndex = INVALID_POSITION;
-        mItemCount = 0;
-        mFromIndex = 0;
-        mToIndex = 0;
-        mScrollX = 0;
-        mScrollY = 0;
-        mAddedCount = 0;
-        mRemovedCount = 0;
+        mCurrentItemIndex = UNDEFINED;
+        mItemCount = UNDEFINED;
+        mFromIndex = UNDEFINED;
+        mToIndex = UNDEFINED;
+        mScrollX = UNDEFINED;
+        mScrollY = UNDEFINED;
+        mAddedCount = UNDEFINED;
+        mRemovedCount = UNDEFINED;
         mClassName = null;
         mContentDescription = null;
         mBeforeText = null;
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/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index abe3c2c..5ec1ec3 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -34,7 +34,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 
 class ComposingText implements NoCopySpan {
 }
@@ -502,7 +502,7 @@
                 }
             }
             if (h != null) {
-                h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+                h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
                         event));
             }
         }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a1a7281..e5f3fc9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -42,7 +42,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -655,7 +655,7 @@
                 if (vh != null) {
                     // This will result in a call to reportFinishInputConnection()
                     // below.
-                    vh.sendMessage(vh.obtainMessage(ViewAncestor.FINISH_INPUT_CONNECTION,
+                    vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
                             mServedInputConnection));
                 }
             }
@@ -1112,9 +1112,9 @@
 
     void scheduleCheckFocusLocked(View view) {
         Handler vh = view.getHandler();
-        if (vh != null && !vh.hasMessages(ViewAncestor.CHECK_FOCUS)) {
+        if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) {
             // This will result in a call to checkFocus() below.
-            vh.sendMessage(vh.obtainMessage(ViewAncestor.CHECK_FOCUS));
+            vh.sendMessage(vh.obtainMessage(ViewRootImpl.CHECK_FOCUS));
         }
     }
     
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 5aa60f4..738bcb9 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -35,7 +35,7 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Surface;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 
 import junit.framework.Assert;
@@ -228,7 +228,7 @@
             sConfigCallback = new ConfigCallback(
                     (WindowManager) appContext.getSystemService(
                             Context.WINDOW_SERVICE));
-            ViewAncestor.addConfigCallback(sConfigCallback);
+            ViewRootImpl.addConfigCallback(sConfigCallback);
         }
         sConfigCallback.addHandler(this);
 
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 32c44d8..d7429b3 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -431,7 +431,6 @@
      */
     public Intent chooseActivity(int index) {
         ActivityResolveInfo chosenActivity = mActivites.get(index);
-        ActivityResolveInfo defaultActivity = mActivites.get(0);
 
         ComponentName chosenName = new ComponentName(
                 chosenActivity.resolveInfo.activityInfo.packageName,
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index f500b39..5b69aa8 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
@@ -92,6 +93,11 @@
     private final ImageButton mDefaultActionButton;
 
     /**
+     * The maximal width of the list popup.
+     */
+    private final int mListPopupMaxWidth;
+
+    /**
      * Observer for the model data.
      */
     private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
@@ -185,7 +191,7 @@
 
         mExpandActivityOverflowButton = (ImageButton) findViewById(R.id.expand_activities_button);
         mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
-        mExpandActivityOverflowButton.setBackgroundDrawable(expandActivityOverflowButtonDrawable);
+        mExpandActivityOverflowButton.setImageDrawable(expandActivityOverflowButtonDrawable);
 
         mAdapter = new ActivityChooserViewAdapter();
         mAdapter.registerDataSetObserver(new DataSetObserver() {
@@ -195,6 +201,10 @@
                 updateButtons();
             }
         });
+
+        Resources resources = context.getResources();
+        mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
+              resources.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
     }
 
     /**
@@ -220,7 +230,7 @@
      * @param drawable The drawable.
      */
     public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
-        mExpandActivityOverflowButton.setBackgroundDrawable(drawable);
+        mExpandActivityOverflowButton.setImageDrawable(drawable);
     }
 
     /**
@@ -264,7 +274,8 @@
             } else {
                 mAdapter.setShowDefaultActivity(false);
             }
-            popupWindow.setContentWidth(mAdapter.measureContentWidth());
+            final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
+            popupWindow.setContentWidth(contentWidth);
             popupWindow.show();
         }
     }
@@ -390,7 +401,7 @@
             }
             ResolveInfo activity = mAdapter.getDefaultActivity();
             PackageManager packageManager = mContext.getPackageManager();
-            mDefaultActionButton.setBackgroundDrawable(activity.loadIcon(packageManager));
+            mDefaultActionButton.setImageDrawable(activity.loadIcon(packageManager));
         } else {
             mDefaultActionButton.setVisibility(View.INVISIBLE);
             mExpandActivityOverflowButton.setEnabled(false);
@@ -574,7 +585,7 @@
                     // Set the icon
                     ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
                     ResolveInfo activity = (ResolveInfo) getItem(position);
-                    iconView.setBackgroundDrawable(activity.loadIcon(packageManager));
+                    iconView.setImageDrawable(activity.loadIcon(packageManager));
                     // Set the title.
                     TextView titleView = (TextView) convertView.findViewById(R.id.title);
                     titleView.setText(activity.loadLabel(packageManager));
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 2410eb2..d3cdad8 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -217,6 +217,7 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
+        info.setCheckable(true);
         info.setChecked(mChecked);
     }
 
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/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 2e0cc62..665109a 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -162,14 +162,17 @@
                 .setOnMenuItemClickListener(mOnMenuItemClickListener);
         }
 
-        // Add a sub-menu for showing all activities as a list item.
-        SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
-                collapsedActivityCount, mContext.getString(R.string.activity_chooser_view_see_all));
-        for (int i = 0; i < expandedActivityCount; i++) {
-            ResolveInfo activity = dataModel.getActivity(i);
-            expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
-                .setIcon(activity.loadIcon(packageManager))
-                .setOnMenuItemClickListener(mOnMenuItemClickListener);
+        if (collapsedActivityCount < expandedActivityCount) {
+            // Add a sub-menu for showing all activities as a list item.
+            SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
+                    collapsedActivityCount,
+                    mContext.getString(R.string.activity_chooser_view_see_all));
+            for (int i = 0; i < expandedActivityCount; i++) {
+                ResolveInfo activity = dataModel.getActivity(i);
+                expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
+                    .setIcon(activity.loadIcon(packageManager))
+                    .setOnMenuItemClickListener(mOnMenuItemClickListener);
+            }
         }
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 769f5e3..66a07d3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -117,7 +117,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
@@ -3731,13 +3731,13 @@
         Handler h = getHandler();
         if (h != null) {
             long eventTime = SystemClock.uptimeMillis();
-            h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+            h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
                     new KeyEvent(eventTime, eventTime,
                     KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                     KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
                     | KeyEvent.FLAG_EDITOR_ACTION)));
-            h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+            h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
                     new KeyEvent(SystemClock.uptimeMillis(), eventTime,
                     KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 9e37c7b..f3d891d 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -33,7 +33,7 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.View.OnClickListener;
 import android.view.WindowManager.LayoutParams;
@@ -501,7 +501,7 @@
 
         } else {
 
-            ViewAncestor viewRoot = getOwnerViewAncestor();
+            ViewRootImpl viewRoot = getOwnerViewRootImpl();
             if (viewRoot != null) {
                 viewRoot.dispatchKey(event);
             }
@@ -526,15 +526,15 @@
         }
     }
 
-    private ViewAncestor getOwnerViewAncestor() {
+    private ViewRootImpl getOwnerViewRootImpl() {
         View rootViewOfOwner = mOwnerView.getRootView();
         if (rootViewOfOwner == null) {
             return null;
         }
 
         ViewParent parentOfRootView = rootViewOfOwner.getParent();
-        if (parentOfRootView instanceof ViewAncestor) {
-            return (ViewAncestor) parentOfRootView;
+        if (parentOfRootView instanceof ViewRootImpl) {
+            return (ViewRootImpl) parentOfRootView;
         } else {
             return null;
         }
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 6039cc2..e1166f1 100755
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -23,6 +23,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.widget.Toast;
 import android.util.Log;
 import android.location.LocationManager;
@@ -44,8 +46,12 @@
     private static final int POSITIVE_BUTTON = AlertDialog.BUTTON_POSITIVE;
     private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON_NEGATIVE;
 
+    private static final int GPS_NO_RESPONSE_TIME_OUT = 1;
     // Received ID from intent, -1 when no notification is in progress
     private int notificationId = -1;
+    private int timeout = -1;
+    private int default_response = -1;
+    private int default_response_timeout = 6;
 
     /** Used to detect when NI request is received */
     private BroadcastReceiver mNetInitiatedReceiver = new BroadcastReceiver() {
@@ -58,6 +64,21 @@
         }
     };
 
+    private final Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case GPS_NO_RESPONSE_TIME_OUT: {
+                if (notificationId != -1) {
+                    sendUserResponse(default_response);
+                }
+                finish();
+            }
+            break;
+            default:
+            }
+        }
+    };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -75,8 +96,11 @@
         p.mNegativeButtonListener = this;
 
         notificationId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
-        if (DEBUG) Log.d(TAG, "onCreate, notifId: " + notificationId);
+        timeout = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TIMEOUT, default_response_timeout);
+        default_response = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_DEFAULT_RESPONSE, GpsNetInitiatedHandler.GPS_NI_RESPONSE_ACCEPT);
+        if (DEBUG) Log.d(TAG, "onCreate() : notificationId: " + notificationId + " timeout: " + timeout + " default_response:" + default_response);
 
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(GPS_NO_RESPONSE_TIME_OUT), (timeout * 1000));
         setupAlert();
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 6bb40a4..678751c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -370,6 +370,19 @@
         mMenuView = menuView;
     }
 
+    public boolean hasExpandedActionView() {
+        return mExpandedMenuPresenter != null &&
+                mExpandedMenuPresenter.mCurrentExpandedItem != null;
+    }
+
+    public void collapseActionView() {
+        final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
+                mExpandedMenuPresenter.mCurrentExpandedItem;
+        if (item != null) {
+            item.collapseActionView();
+        }
+    }
+
     public void setCustomNavigationView(View view) {
         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
         if (mCustomNavView != null && showCustom) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d034eab..bbddf29 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -114,6 +114,23 @@
     private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false);
     private static FileObserver sPasswordObserver;
 
+    private static class PasswordFileObserver extends FileObserver {
+        public PasswordFileObserver(String path, int mask) {
+            super(path, mask);
+        }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if (LOCK_PATTERN_FILE.equals(path)) {
+                Log.d(TAG, "lock pattern file changed");
+                sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
+            } else if (LOCK_PASSWORD_FILE.equals(path)) {
+                Log.d(TAG, "lock password file changed");
+                sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
+            }
+        }
+    }
+
     public DevicePolicyManager getDevicePolicyManager() {
         if (mDevicePolicyManager == null) {
             mDevicePolicyManager =
@@ -143,18 +160,7 @@
             sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
             int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
                     FileObserver.MOVED_TO | FileObserver.CREATE;
-            sPasswordObserver = new FileObserver(dataSystemDirectory, fileObserverMask) {
-                    @Override
-                    public void onEvent(int event, String path) {
-                        if (LOCK_PATTERN_FILE.equals(path)) {
-                            Log.d(TAG, "lock pattern file changed");
-                            sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
-                        } else if (LOCK_PASSWORD_FILE.equals(path)) {
-                            Log.d(TAG, "lock password file changed");
-                            sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
-                        }
-                    }
-                };
+            sPasswordObserver = new PasswordFileObserver(dataSystemDirectory, fileObserverMask);
             sPasswordObserver.startWatching();
         }
     }
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 3070e3e..fb33748 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -29,7 +29,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewAncestor;
+import android.view.ViewRootImpl;
 import com.android.internal.R;
 
 public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
@@ -150,7 +150,7 @@
                 KeyEvent event = events[i];
                 event = KeyEvent.changeFlags(event, event.getFlags()
                         | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
-                handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY, event));
+                handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY, event));
             }
         }
     }
@@ -158,11 +158,11 @@
     public void sendDownUpKeyEvents(int keyEventCode) {
         long eventTime = SystemClock.uptimeMillis();
         Handler handler = mTargetView.getHandler();
-        handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+        handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
                 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                     KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
-        handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
+        handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
                 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                         KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 08431cd..6ab8fe3 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -627,15 +627,6 @@
         "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
     mOptions.add(opt);
 
-    char enableDPBuf[sizeof("-Xdeadlockpredict:") + PROPERTY_VALUE_MAX];
-    property_get("dalvik.vm.deadlock-predict", propBuf, "");
-    if (strlen(propBuf) > 0) {
-        strcpy(enableDPBuf, "-Xdeadlockpredict:");
-        strcat(enableDPBuf, propBuf);
-        opt.optionString = enableDPBuf;
-        mOptions.add(opt);
-    }
-
     LOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
     if (checkJni) {
         /* extended JNI checking */
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_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index a4432c3..3a3f07e 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -27,6 +27,7 @@
 #include <sys/time.h>
 #include <errno.h>
 #include <assert.h>
+#include <ctype.h>
 
 #ifdef HAVE_MALLOC_H
 #include <malloc.h>
@@ -35,28 +36,50 @@
 namespace android
 {
 
-static jfieldID dalvikPss_field;
-static jfieldID dalvikPrivateDirty_field;
-static jfieldID dalvikSharedDirty_field;
-static jfieldID nativePss_field;
-static jfieldID nativePrivateDirty_field;
-static jfieldID nativeSharedDirty_field;
-static jfieldID otherPss_field;
-static jfieldID otherPrivateDirty_field;
-static jfieldID otherSharedDirty_field;
+enum {
+    HEAP_UNKNOWN,
+    HEAP_DALVIK,
+    HEAP_NATIVE,
+    HEAP_CURSOR,
+    HEAP_ASHMEM,
+    HEAP_UNKNOWN_DEV,
+    HEAP_SO,
+    HEAP_JAR,
+    HEAP_APK,
+    HEAP_TTF,
+    HEAP_DEX,
+    HEAP_UNKNOWN_MAP,
+
+    _NUM_HEAP,
+    _NUM_CORE_HEAP = HEAP_NATIVE+1
+};
+
+struct stat_fields {
+    jfieldID pss_field;
+    jfieldID privateDirty_field;
+    jfieldID sharedDirty_field;
+};
+
+struct stat_field_names {
+    const char* pss_name;
+    const char* privateDirty_name;
+    const char* sharedDirty_name;
+};
+
+static stat_fields stat_fields[_NUM_CORE_HEAP];
+
+static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
+    { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
+    { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
+    { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
+};
+
+jfieldID otherStats_field;
 
 struct stats_t {
-    int dalvikPss;
-    int dalvikPrivateDirty;
-    int dalvikSharedDirty;
-    
-    int nativePss;
-    int nativePrivateDirty;
-    int nativeSharedDirty;
-    
-    int otherPss;
-    int otherPrivateDirty;
-    int otherSharedDirty;
+    int pss;
+    int privateDirty;
+    int sharedDirty;
 };
 
 #define BINDER_STATS "/proc/binder/stats"
@@ -94,48 +117,71 @@
 static void read_mapinfo(FILE *fp, stats_t* stats)
 {
     char line[1024];
-    int len;
+    int len, nameLen;
     bool skip, done = false;
 
-    unsigned start = 0, size = 0, resident = 0, pss = 0;
+    unsigned size = 0, resident = 0, pss = 0;
     unsigned shared_clean = 0, shared_dirty = 0;
     unsigned private_clean = 0, private_dirty = 0;
     unsigned referenced = 0;
     unsigned temp;
 
-    int isNativeHeap;
-    int isDalvikHeap;
-    int isSqliteHeap;
+    unsigned long int start;
+    unsigned long int end = 0;
+    unsigned long int prevEnd = 0;
+    char* name;
+    int name_pos;
 
-    if(fgets(line, 1024, fp) == 0) return;
+    int whichHeap = HEAP_UNKNOWN;
+    int prevHeap = HEAP_UNKNOWN;
+
+    if(fgets(line, sizeof(line), fp) == 0) return;
 
     while (!done) {
-        isNativeHeap = 0;
-        isDalvikHeap = 0;
-        isSqliteHeap = 0;
+        prevHeap = whichHeap;
+        prevEnd = end;
+        whichHeap = HEAP_UNKNOWN;
         skip = false;
 
         len = strlen(line);
         if (len < 1) return;
         line[--len] = 0;
 
-        /* ignore guard pages */
-        if (len > 18 && line[17] == '-') skip = true;
+        if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+            skip = true;
+        } else {
+            while (isspace(line[name_pos])) {
+                name_pos += 1;
+            }
+            name = line + name_pos;
+            nameLen = strlen(name);
 
-        start = strtoul(line, 0, 16);
-
-        if (strstr(line, "[heap]")) {
-            isNativeHeap = 1;
-        } else if (strstr(line, "/dalvik-LinearAlloc")) {
-            isDalvikHeap = 1;
-        } else if (strstr(line, "/mspace/dalvik-heap")) {
-            isDalvikHeap = 1;
-        } else if (strstr(line, "/dalvik-heap-bitmap/")) {
-            isDalvikHeap = 1;    
-        } else if (strstr(line, "/data/dalvik-cache/")) {
-            isDalvikHeap = 1;
-        } else if (strstr(line, "/tmp/sqlite-heap")) {
-            isSqliteHeap = 1;
+            if (strstr(name, "[heap]") == name) {
+                whichHeap = HEAP_NATIVE;
+            } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
+                whichHeap = HEAP_DALVIK;
+            } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
+                whichHeap = HEAP_CURSOR;
+            } else if (strstr(name, "/dev/ashmem/") == name) {
+                whichHeap = HEAP_ASHMEM;
+            } else if (strstr(name, "/dev/") == name) {
+                whichHeap = HEAP_UNKNOWN_DEV;
+            } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
+                whichHeap = HEAP_SO;
+            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
+                whichHeap = HEAP_JAR;
+            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
+                whichHeap = HEAP_APK;
+            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
+                whichHeap = HEAP_TTF;
+            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) {
+                whichHeap = HEAP_DEX;
+            } else if (nameLen > 0) {
+                whichHeap = HEAP_UNKNOWN_MAP;
+            } else if (start == prevEnd && prevHeap == HEAP_SO) {
+                // bss section of a shared library.
+                whichHeap = HEAP_SO;
+            }
         }
 
         //LOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
@@ -171,21 +217,9 @@
         }
 
         if (!skip) {
-            if (isNativeHeap) {
-                stats->nativePss += pss;
-                stats->nativePrivateDirty += private_dirty;
-                stats->nativeSharedDirty += shared_dirty;
-            } else if (isDalvikHeap) {
-                stats->dalvikPss += pss;
-                stats->dalvikPrivateDirty += private_dirty;
-                stats->dalvikSharedDirty += shared_dirty;
-            } else if ( isSqliteHeap) {
-                // ignore
-            } else {
-                stats->otherPss += pss;
-                stats->otherPrivateDirty += private_dirty;
-                stats->otherSharedDirty += shared_dirty;
-            }
+            stats[whichHeap].pss += pss;
+            stats[whichHeap].privateDirty += private_dirty;
+            stats[whichHeap].sharedDirty += shared_dirty;
         }
     }
 }
@@ -206,22 +240,38 @@
 static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
         jint pid, jobject object)
 {
-    stats_t stats;
-    memset(&stats, 0, sizeof(stats_t));
+    stats_t stats[_NUM_HEAP];
+    memset(&stats, 0, sizeof(stats));
     
-    load_maps(pid, &stats);
+    load_maps(pid, stats);
 
-    env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
-    env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
-    env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty);
+    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+        stats[HEAP_UNKNOWN].pss += stats[i].pss;
+        stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
+        stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
+    }
+
+    for (int i=0; i<_NUM_CORE_HEAP; i++) {
+        env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
+        env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
+        env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
+    }
     
-    env->SetIntField(object, nativePss_field, stats.nativePss);
-    env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty);
-    env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty);
+    jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
     
-    env->SetIntField(object, otherPss_field, stats.otherPss);
-    env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty);
-    env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
+    jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
+    if (otherArray == NULL) {
+        return;
+    }
+
+    int j=0;
+    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+        otherArray[j++] = stats[i].pss;
+        otherArray[j++] = stats[i].privateDirty;
+        otherArray[j++] = stats[i].sharedDirty;
+    }
+
+    env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
 }
 
 static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
@@ -487,19 +537,18 @@
 int register_android_os_Debug(JNIEnv *env)
 {
     jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
-    
-    dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I");
-    dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I");
-    dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I");
 
-    nativePss_field = env->GetFieldID(clazz, "nativePss", "I");
-    nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I");
-    nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I");
-    
-    otherPss_field = env->GetFieldID(clazz, "otherPss", "I");
-    otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I");
-    otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I");
-    
+    for (int i=0; i<_NUM_CORE_HEAP; i++) {
+        stat_fields[i].pss_field =
+                env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
+        stat_fields[i].privateDirty_field =
+                env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
+        stat_fields[i].sharedDirty_field =
+                env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
+    }
+
+    otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
+
     return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 681f43f..b0c2f2c 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -127,6 +127,13 @@
     }
 }
 
+static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
+        Caches::FlushMode mode) {
+    if (Caches::hasInstance()) {
+        Caches::getInstance().flush(mode);
+    }
+}
+
 // ----------------------------------------------------------------------------
 // Constructors
 // ----------------------------------------------------------------------------
@@ -735,6 +742,7 @@
     { "nIsBackBufferPreserved", "()Z",         (void*) android_view_GLES20Canvas_isBackBufferPreserved },
     { "nPreserveBackBuffer",    "()Z",         (void*) android_view_GLES20Canvas_preserveBackBuffer },
     { "nDisableVsync",          "()V",         (void*) android_view_GLES20Canvas_disableVsync },
+    { "nFlushCaches",           "(I)V",        (void*) android_view_GLES20Canvas_flushCaches },
 
     { "nCreateRenderer",    "()I",             (void*) android_view_GLES20Canvas_createRenderer },
     { "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
@@ -859,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/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml
index 902b3c0..50b1878 100644
--- a/core/res/res/layout/activity_chooser_view.xml
+++ b/core/res/res/layout/activity_chooser_view.xml
@@ -23,13 +23,9 @@
     style="?android:attr/actionButtonStyle">
 
     <ImageButton android:id="@+id/default_activity_button"
-        android:layout_width="32dip"
-        android:layout_height="32dip"
-        android:layout_marginRight="8dip" />
+        style="@style/Widget.ActivityChooserViewButton" />
 
     <ImageButton android:id="@+id/expand_activities_button"
-        android:layout_width="32dip"
-        android:layout_height="32dip"
-        android:layout_marginLeft="8dip" />
+        style="@style/Widget.ActivityChooserViewButton" />
 
 </LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_view_list_item.xml b/core/res/res/layout/activity_chooser_view_list_item.xml
index f90044e..88498d9 100644
--- a/core/res/res/layout/activity_chooser_view_list_item.xml
+++ b/core/res/res/layout/activity_chooser_view_list_item.xml
@@ -20,6 +20,7 @@
     android:layout_height="?android:attr/dropdownListPreferredItemHeight"
     android:paddingLeft="16dip"
     android:paddingRight="16dip"
+    android:minWidth="196dip"
     android:background="?android:attr/activatedBackgroundIndicator"
     android:orientation="vertical" >
 
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/config.xml b/core/res/res/values/config.xml
index 1f2b7fb..215700c 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -665,4 +665,7 @@
     <!-- Timeout to wait for NTP server response. -->
     <integer name="config_ntpTimeout">20000</integer>
 
+    <!-- Default network policy warning threshold, in megabytes. -->
+    <integer name="config_networkPolicyDefaultWarning">2048</integer>
+
 </resources>
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/res/res/values/public.xml b/core/res/res/values/public.xml
index 6dedc83..f464623 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1787,6 +1787,11 @@
   <public type="attr" name="colorActivatedHighlight" />
   <public type="attr" name="colorMultiSelectHighlight" />
 
+  <public type="attr" name="drawableStart" />
+  <public type="attr" name="drawableEnd" />
+
+  <public type="attr" name="actionModeStyle" />
+
   <public type="style" name="TextAppearance.SuggestionHighlight" />
   <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
   <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
@@ -1826,7 +1831,4 @@
   <public type="color" name="holo_purple" />
   <public type="color" name="holo_blue_bright" />
 
-  <public type="attr" name="drawableStart" />
-  <public type="attr" name="drawableEnd" />
-
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6b75146..5b5e7c3 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -713,6 +713,16 @@
         <item name="android:quickContactWindowSize">modeLarge</item>
     </style>
 
+    <style name="Widget.ActivityChooserViewButton">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_gravity">center</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:adjustViewBounds">true</item>
+        <item name="android:scaleType">fitCenter</item>
+        <item name="android:padding">@android:dimen/action_bar_icon_vertical_padding</item>
+    </style>
+
     <!-- Text Appearances -->
     <eat-comment />
 
diff --git a/core/tests/coretests/src/android/content/ObserverNodeTest.java b/core/tests/coretests/src/android/content/ObserverNodeTest.java
index 736c759..95b8465 100644
--- a/core/tests/coretests/src/android/content/ObserverNodeTest.java
+++ b/core/tests/coretests/src/android/content/ObserverNodeTest.java
@@ -48,9 +48,9 @@
         int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
 
         // special case
-        root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root);
+        root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root, 0, 0);
         for(int i = 1; i < uris.length; i++) {
-            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root);
+            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root, 0, 0);
         }
 
         ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
@@ -77,7 +77,7 @@
         int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
 
         for(int i = 0; i < uris.length; i++) {
-            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root);
+            root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root, 0, 0);
         }
 
         ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
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/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index a042ddb..20fcde5 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -355,7 +355,7 @@
 
 status_t QueryCodecs(
         const sp<IOMX> &omx,
-        const char *mimeType, bool queryDecoders,
+        const char *mimeType, bool queryDecoders, bool hwCodecOnly,
         Vector<CodecCapabilities> *results);
 
 }  // 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/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index e232ddd..7114b6a 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -33,6 +33,16 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
+// Macros
+///////////////////////////////////////////////////////////////////////////////
+
+#if DEBUG_CACHE_FLUSH
+    #define FLUSH_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define FLUSH_LOGD(...)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -150,6 +160,30 @@
     mLayerGarbage.push(layer);
 }
 
+void Caches::flush(FlushMode mode) {
+    FLUSH_LOGD("Flushing caches (mode %d)", mode);
+
+    clearGarbage();
+
+    switch (mode) {
+        case kFlushMode_Full:
+            textureCache.clear();
+            patchCache.clear();
+            dropShadowCache.clear();
+            gradientCache.clear();
+            // fall through
+        case kFlushMode_Moderate:
+            layerCache.clear();
+            pathCache.clear();
+            roundRectShapeCache.clear();
+            circleShapeCache.clear();
+            ovalShapeCache.clear();
+            rectShapeCache.clear();
+            arcShapeCache.clear();
+            break;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // VBO
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e64d8ac..76dff4b 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -100,6 +100,18 @@
     Vector<Layer*> mLayerGarbage;
 
 public:
+    enum FlushMode {
+        kFlushMode_Moderate = 0,
+        kFlushMode_Full
+    };
+
+    /**
+     * Flush the cache.
+     *
+     * @param mode Indicates how much of the cache should be flushed
+     */
+    void flush(FlushMode mode);
+
     /**
      * Indicates whether the renderer is in debug mode.
      * This debug mode provides limited information to app developers.
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 2cdc8c3..5db73db 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -26,6 +26,9 @@
 // Turn on to enable memory usage summary on each frame
 #define DEBUG_MEMORY_USAGE 0
 
+// Turn on to enable debugging of cache flushes
+#define DEBUG_CACHE_FLUSH 1
+
 // Turn on to enable layers debugging when rendered as regions
 #define DEBUG_LAYERS_AS_REGIONS 0
 
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/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
new file mode 100755
index 0000000..77d40b6
--- /dev/null
+++ b/media/libeffects/preprocessing/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+# audio preprocessing wrapper
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libaudiopreprocessing
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+
+LOCAL_SRC_FILES:= \
+    PreProcessing.cpp
+
+LOCAL_C_INCLUDES += \
+    external/webrtc/src \
+    external/webrtc/src/modules/interface \
+    external/webrtc/src/modules/audio_processing/main/interface \
+    system/media/audio_effects/include
+
+LOCAL_C_INCLUDES += $(call include-path-for, speex)
+
+LOCAL_SHARED_LIBRARIES := \
+    libwebrtc_audio_preprocessing \
+    libspeexresampler \
+    libutils
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_LDLIBS += -ldl
+else
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
new file mode 100755
index 0000000..ba286a1
--- /dev/null
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -0,0 +1,1609 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#define LOG_TAG "PreProcessing"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <hardware/audio_effect.h>
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_agc.h>
+#include <audio_effects/effect_ns.h>
+#include "modules/interface/module_common_types.h"
+#include "modules/audio_processing/main/interface/audio_processing.h"
+#include "speex/speex_resampler.h"
+
+
+//------------------------------------------------------------------------------
+// local definitions
+//------------------------------------------------------------------------------
+
+// maximum number of sessions
+#define PREPROC_NUM_SESSIONS 8
+
+// types of pre processing modules
+enum preproc_id
+{
+    PREPROC_AGC,        // Automatic Gain Control
+    PREPROC_AEC,        // Acoustic Echo Canceler
+    PREPROC_NS,         // Noise Suppressor
+    PREPROC_NUM_EFFECTS
+};
+
+// Session state
+enum preproc_session_state {
+    PREPROC_SESSION_STATE_INIT,        // initialized
+    PREPROC_SESSION_STATE_CONFIG       // configuration received
+};
+
+// Effect/Preprocessor state
+enum preproc_effect_state {
+    PREPROC_EFFECT_STATE_INIT,         // initialized
+    PREPROC_EFFECT_STATE_CREATED,      // webRTC engine created
+    PREPROC_EFFECT_STATE_CONFIG,       // configuration received/disabled
+    PREPROC_EFFECT_STATE_ACTIVE        // active/enabled
+};
+
+// handle on webRTC engine
+typedef void* preproc_fx_handle_t;
+
+typedef struct preproc_session_s preproc_session_t;
+typedef struct preproc_effect_s preproc_effect_t;
+typedef struct preproc_ops_s preproc_ops_t;
+
+// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
+// Function pointer can be null if no action required.
+struct preproc_ops_s {
+    int (* create)(preproc_effect_t *fx);
+    int (* init)(preproc_effect_t *fx);
+    int (* reset)(preproc_effect_t *fx);
+    void (* enable)(preproc_effect_t *fx);
+    void (* disable)(preproc_effect_t *fx);
+    int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
+    int (* get_parameter)(preproc_effect_t *fx, void *param, size_t *size, void *value);
+    int (* set_device)(preproc_effect_t *fx, uint32_t device);
+};
+
+// Effect context
+struct preproc_effect_s {
+    const struct effect_interface_s *itfe;
+    uint32_t procId;                // type of pre processor (enum preproc_id)
+    uint32_t state;                 // current state (enum preproc_effect_state)
+    preproc_session_t *session;     // session the effect is on
+    const preproc_ops_t *ops;       // effect ops table
+    preproc_fx_handle_t engine;     // handle on webRTC engine
+};
+
+// Session context
+struct preproc_session_s {
+    struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
+    uint32_t state;                     // current state (enum preproc_session_state)
+    int id;                             // audio session ID
+    int io;                             // handle of input stream this session is on
+    webrtc::AudioProcessing* apm;       // handle on webRTC audio processing module (APM)
+    size_t apmFrameCount;               // buffer size for webRTC process (10 ms)
+    uint32_t apmSamplingRate;           // webRTC APM sampling rate (8/16 or 32 kHz)
+    size_t frameCount;                  // buffer size before input resampler ( <=> apmFrameCount)
+    uint32_t samplingRate;              // sampling rate at effect process interface
+    uint32_t inChannelCount;            // input channel count
+    uint32_t outChannelCount;           // output channel count
+    uint32_t createdMsk;                // bit field containing IDs of crested pre processors
+    uint32_t enabledMsk;                // bit field containing IDs of enabled pre processors
+    uint32_t processedMsk;              // bit field containing IDs of pre processors already
+                                        // processed in current round
+    webrtc::AudioFrame *procFrame;      // audio frame passed to webRTC AMP ProcessStream()
+    int16_t *inBuf;                     // input buffer used when resampling
+    size_t inBufSize;                   // input buffer size in frames
+    size_t framesIn;                    // number of frames in input buffer
+    SpeexResamplerState *inResampler;   // handle on input speex resampler
+    int16_t *outBuf;                    // output buffer used when resampling
+    size_t outBufSize;                  // output buffer size in frames
+    size_t framesOut;                   // number of frames in output buffer
+    SpeexResamplerState *outResampler;  // handle on output speex resampler
+    uint32_t revChannelCount;           // number of channels on reverse stream
+    uint32_t revEnabledMsk;             // bit field containing IDs of enabled pre processors
+                                        // with reverse channel
+    uint32_t revProcessedMsk;           // bit field containing IDs of pre processors with reverse
+                                        // channel already processed in current round
+    webrtc::AudioFrame *revFrame;       // audio frame passed to webRTC AMP AnalyzeReverseStream()
+    int16_t *revBuf;                    // reverse channel input buffer
+    size_t revBufSize;                  // reverse channel input buffer size
+    size_t framesRev;                   // number of frames in reverse channel input buffer
+    SpeexResamplerState *revResampler;  // handle on reverse channel input speex resampler
+};
+
+//------------------------------------------------------------------------------
+// Effect descriptors
+//------------------------------------------------------------------------------
+
+// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
+// as the pre processing effects are not defined by OpenSL ES
+
+// Automatic Gain Control
+static const effect_descriptor_t sAgcDescriptor = {
+        { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+        { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+        0, //FIXME indicate CPU load
+        0, //FIXME indicate memory usage
+        "Automatic Gain Control",
+        "The Android Open Source Project"
+};
+
+// Acoustic Echo Cancellation
+static const effect_descriptor_t sAecDescriptor = {
+        { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+        { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+        0, //FIXME indicate CPU load
+        0, //FIXME indicate memory usage
+        "Acoustic Echo Canceler",
+        "The Android Open Source Project"
+};
+
+// Noise suppression
+static const effect_descriptor_t sNsDescriptor = {
+        { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+        { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+        0, //FIXME indicate CPU load
+        0, //FIXME indicate memory usage
+        "Noise Suppression",
+        "The Android Open Source Project"
+};
+
+
+static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
+        &sAgcDescriptor,
+        &sAecDescriptor,
+        &sNsDescriptor
+};
+
+//------------------------------------------------------------------------------
+// Helper functions
+//------------------------------------------------------------------------------
+
+const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
+        FX_IID_AGC,
+        FX_IID_AEC,
+        FX_IID_NS
+};
+
+
+const effect_uuid_t * ProcIdToUuid(int procId)
+{
+    if (procId >= PREPROC_NUM_EFFECTS) {
+        return EFFECT_UUID_NULL;
+    }
+    return sUuidToPreProcTable[procId];
+}
+
+uint32_t UuidToProcId(const effect_uuid_t * uuid)
+{
+    size_t i;
+    for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
+        if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
+            break;
+        }
+    }
+    return i;
+}
+
+bool HasReverseStream(uint32_t procId)
+{
+    if (procId == PREPROC_AEC) {
+        return true;
+    }
+    return false;
+}
+
+
+//------------------------------------------------------------------------------
+// Automatic Gain Control (AGC)
+//------------------------------------------------------------------------------
+
+static const int kAgcDefaultTargetLevel = 0;
+static const int kAgcDefaultCompGain = 90;
+static const bool kAgcDefaultLimiter = true;
+
+int  AgcInit (preproc_effect_t *effect)
+{
+    LOGV("AgcInit");
+    webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+    agc->set_mode(webrtc::GainControl::kFixedDigital);
+    agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
+    agc->set_compression_gain_db(kAgcDefaultCompGain);
+    agc->enable_limiter(kAgcDefaultLimiter);
+    return 0;
+}
+
+int  AgcCreate(preproc_effect_t *effect)
+{
+    webrtc::GainControl *agc = effect->session->apm->gain_control();
+    LOGV("AgcCreate got agc %p", agc);
+    if (agc == NULL) {
+        LOGW("AgcCreate Error");
+        return -ENOMEM;
+    }
+    effect->engine = static_cast<preproc_fx_handle_t>(agc);
+    AgcInit(effect);
+    return 0;
+}
+
+int AgcGetParameter(preproc_effect_t *effect,
+                    void *pParam,
+                    size_t *pValueSize,
+                    void *pValue)
+{
+    int status = 0;
+    uint32_t param = *(uint32_t *)pParam;
+    t_agc_settings *pProperties = (t_agc_settings *)pValue;
+    webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+
+    switch (param) {
+    case AGC_PARAM_TARGET_LEVEL:
+    case AGC_PARAM_COMP_GAIN:
+        if (*pValueSize < sizeof(int16_t)) {
+            *pValueSize = 0;
+            return -EINVAL;
+        }
+        break;
+    case AGC_PARAM_LIMITER_ENA:
+        if (*pValueSize < sizeof(bool)) {
+            *pValueSize = 0;
+            return -EINVAL;
+        }
+        break;
+    case AGC_PARAM_PROPERTIES:
+        if (*pValueSize < sizeof(t_agc_settings)) {
+            *pValueSize = 0;
+            return -EINVAL;
+        }
+        break;
+
+    default:
+        LOGW("AgcGetParameter() unknown param %08x", param);
+        status = -EINVAL;
+        break;
+    }
+
+    switch (param) {
+    case AGC_PARAM_TARGET_LEVEL:
+        *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
+        LOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
+        break;
+    case AGC_PARAM_COMP_GAIN:
+        *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
+        LOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
+        break;
+    case AGC_PARAM_LIMITER_ENA:
+        *(bool *) pValue = (bool)agc->is_limiter_enabled();
+        LOGV("AgcGetParameter() limiter enabled %s",
+             (*(int16_t *) pValue != 0) ? "true" : "false");
+        break;
+    case AGC_PARAM_PROPERTIES:
+        pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
+        pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
+        pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
+        break;
+    default:
+        LOGW("AgcGetParameter() unknown param %d", param);
+        status = -EINVAL;
+        break;
+    }
+    return status;
+}
+
+int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+    int status = 0;
+    uint32_t param = *(uint32_t *)pParam;
+    t_agc_settings *pProperties = (t_agc_settings *)pValue;
+    webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+
+    switch (param) {
+    case AGC_PARAM_TARGET_LEVEL:
+        LOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
+        status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
+        break;
+    case AGC_PARAM_COMP_GAIN:
+        LOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
+        status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
+        break;
+    case AGC_PARAM_LIMITER_ENA:
+        LOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
+        status = agc->enable_limiter(*(bool *)pValue);
+        break;
+    case AGC_PARAM_PROPERTIES:
+        LOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
+             pProperties->targetLevel,
+             pProperties->compGain,
+             pProperties->limiterEnabled);
+        status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
+        if (status != 0) break;
+        status = agc->set_compression_gain_db(pProperties->compGain / 100);
+        if (status != 0) break;
+        status = agc->enable_limiter(pProperties->limiterEnabled);
+        break;
+    default:
+        LOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+        status = -EINVAL;
+        break;
+    }
+
+    LOGV("AgcSetParameter() done status %d", status);
+
+    return status;
+}
+
+void AgcEnable(preproc_effect_t *effect)
+{
+    webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+    LOGV("AgcEnable agc %p", agc);
+    agc->Enable(true);
+}
+
+void AgcDisable(preproc_effect_t *effect)
+{
+    LOGV("AgcDisable");
+    webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+    agc->Enable(false);
+}
+
+
+static const preproc_ops_t sAgcOps = {
+        AgcCreate,
+        AgcInit,
+        NULL,
+        AgcEnable,
+        AgcDisable,
+        AgcSetParameter,
+        AgcGetParameter,
+        NULL
+};
+
+
+//------------------------------------------------------------------------------
+// Acoustic Echo Canceler (AEC)
+//------------------------------------------------------------------------------
+
+static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
+        webrtc::EchoControlMobile::kEarpiece;
+static const bool kAecDefaultComfortNoise = true;
+
+int  AecInit (preproc_effect_t *effect)
+{
+    LOGV("AecInit");
+    webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+    aec->set_routing_mode(kAecDefaultMode);
+    aec->enable_comfort_noise(kAecDefaultComfortNoise);
+    return 0;
+}
+
+int  AecCreate(preproc_effect_t *effect)
+{
+    webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
+    LOGV("AecCreate got aec %p", aec);
+    if (aec == NULL) {
+        LOGW("AgcCreate Error");
+        return -ENOMEM;
+    }
+    effect->engine = static_cast<preproc_fx_handle_t>(aec);
+    AecInit (effect);
+    return 0;
+}
+
+int AecGetParameter(preproc_effect_t     *effect,
+                    void              *pParam,
+                    size_t            *pValueSize,
+                    void              *pValue)
+{
+    int status = 0;
+    uint32_t param = *(uint32_t *)pParam;
+
+    if (*pValueSize < sizeof(uint32_t)) {
+        return -EINVAL;
+    }
+    switch (param) {
+    case AEC_PARAM_ECHO_DELAY:
+    case AEC_PARAM_PROPERTIES:
+        *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
+        LOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
+        break;
+    default:
+        LOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+        status = -EINVAL;
+        break;
+    }
+    return status;
+}
+
+int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+    int status = 0;
+    uint32_t param = *(uint32_t *)pParam;
+    uint32_t value = *(uint32_t *)pValue;
+
+    switch (param) {
+    case AEC_PARAM_ECHO_DELAY:
+    case AEC_PARAM_PROPERTIES:
+        status = effect->session->apm->set_stream_delay_ms(value/1000);
+        LOGV("AecSetParameter() echo delay %d us, status %d", value, status);
+        break;
+    default:
+        LOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+        status = -EINVAL;
+        break;
+    }
+    return status;
+}
+
+void AecEnable(preproc_effect_t *effect)
+{
+    webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+    LOGV("AecEnable aec %p", aec);
+    aec->Enable(true);
+}
+
+void AecDisable(preproc_effect_t *effect)
+{
+    LOGV("AecDisable");
+    webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+    aec->Enable(false);
+}
+
+int AecSetDevice(preproc_effect_t *effect, uint32_t device)
+{
+    LOGV("AecSetDevice %08x", device);
+    webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+    webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
+
+    switch(device) {
+    case AUDIO_DEVICE_OUT_EARPIECE:
+        mode = webrtc::EchoControlMobile::kEarpiece;
+        break;
+    case AUDIO_DEVICE_OUT_SPEAKER:
+        mode = webrtc::EchoControlMobile::kSpeakerphone;
+        break;
+    case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+    case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+    default:
+        break;
+    }
+    aec->set_routing_mode(mode);
+    return 0;
+}
+
+static const preproc_ops_t sAecOps = {
+        AecCreate,
+        AecInit,
+        NULL,
+        AecEnable,
+        AecDisable,
+        AecSetParameter,
+        AecGetParameter,
+        AecSetDevice
+};
+
+//------------------------------------------------------------------------------
+// Noise Suppression (NS)
+//------------------------------------------------------------------------------
+
+static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
+
+int  NsInit (preproc_effect_t *effect)
+{
+    LOGV("NsInit");
+    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+    ns->set_level(kNsDefaultLevel);
+    return 0;
+}
+
+int  NsCreate(preproc_effect_t *effect)
+{
+    webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
+    LOGV("NsCreate got ns %p", ns);
+    if (ns == NULL) {
+        LOGW("AgcCreate Error");
+        return -ENOMEM;
+    }
+    effect->engine = static_cast<preproc_fx_handle_t>(ns);
+    NsInit (effect);
+    return 0;
+}
+
+int NsGetParameter(preproc_effect_t     *effect,
+                   void              *pParam,
+                   size_t            *pValueSize,
+                   void              *pValue)
+{
+    int status = 0;
+    return status;
+}
+
+int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+    int status = 0;
+    return status;
+}
+
+void NsEnable(preproc_effect_t *effect)
+{
+    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+    LOGV("NsEnable ns %p", ns);
+    ns->Enable(true);
+}
+
+void NsDisable(preproc_effect_t *effect)
+{
+    LOGV("NsDisable");
+    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+    ns->Enable(false);
+}
+
+static const preproc_ops_t sNsOps = {
+        NsCreate,
+        NsInit,
+        NULL,
+        NsEnable,
+        NsDisable,
+        NsSetParameter,
+        NsGetParameter,
+        NULL
+};
+
+
+static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
+        &sAgcOps,
+        &sAecOps,
+        &sNsOps
+};
+
+
+//------------------------------------------------------------------------------
+// Effect functions
+//------------------------------------------------------------------------------
+
+void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
+
+extern "C" const struct effect_interface_s sEffectInterface;
+extern "C" const struct effect_interface_s sEffectInterfaceReverse;
+
+#define BAD_STATE_ABORT(from, to) \
+        LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
+
+int Effect_SetState(preproc_effect_t *effect, uint32_t state)
+{
+    int status = 0;
+    LOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
+    switch(state) {
+    case PREPROC_EFFECT_STATE_INIT:
+        switch(effect->state) {
+        case PREPROC_EFFECT_STATE_ACTIVE:
+            effect->ops->disable(effect);
+            Session_SetProcEnabled(effect->session, effect->procId, false);
+        case PREPROC_EFFECT_STATE_CONFIG:
+        case PREPROC_EFFECT_STATE_CREATED:
+        case PREPROC_EFFECT_STATE_INIT:
+            break;
+        default:
+            BAD_STATE_ABORT(effect->state, state);
+        }
+        break;
+    case PREPROC_EFFECT_STATE_CREATED:
+        switch(effect->state) {
+        case PREPROC_EFFECT_STATE_INIT:
+            status = effect->ops->create(effect);
+            break;
+        case PREPROC_EFFECT_STATE_CREATED:
+        case PREPROC_EFFECT_STATE_ACTIVE:
+        case PREPROC_EFFECT_STATE_CONFIG:
+            LOGE("Effect_SetState invalid transition");
+            status = -ENOSYS;
+            break;
+        default:
+            BAD_STATE_ABORT(effect->state, state);
+        }
+        break;
+    case PREPROC_EFFECT_STATE_CONFIG:
+        switch(effect->state) {
+        case PREPROC_EFFECT_STATE_INIT:
+            LOGE("Effect_SetState invalid transition");
+            status = -ENOSYS;
+            break;
+        case PREPROC_EFFECT_STATE_ACTIVE:
+            effect->ops->disable(effect);
+            Session_SetProcEnabled(effect->session, effect->procId, false);
+            break;
+        case PREPROC_EFFECT_STATE_CREATED:
+        case PREPROC_EFFECT_STATE_CONFIG:
+            break;
+        default:
+            BAD_STATE_ABORT(effect->state, state);
+        }
+        break;
+    case PREPROC_EFFECT_STATE_ACTIVE:
+        switch(effect->state) {
+        case PREPROC_EFFECT_STATE_INIT:
+        case PREPROC_EFFECT_STATE_CREATED:
+        case PREPROC_EFFECT_STATE_ACTIVE:
+            LOGE("Effect_SetState invalid transition");
+            status = -ENOSYS;
+            break;
+        case PREPROC_EFFECT_STATE_CONFIG:
+            effect->ops->enable(effect);
+            Session_SetProcEnabled(effect->session, effect->procId, true);
+            break;
+        default:
+            BAD_STATE_ABORT(effect->state, state);
+        }
+        break;
+    default:
+        BAD_STATE_ABORT(effect->state, state);
+    }
+    if (status == 0) {
+        effect->state = state;
+    }
+    return status;
+}
+
+int Effect_Init(preproc_effect_t *effect, uint32_t procId)
+{
+    if (HasReverseStream(procId)) {
+        effect->itfe = &sEffectInterfaceReverse;
+    } else {
+        effect->itfe = &sEffectInterface;
+    }
+    effect->ops = sPreProcOps[procId];
+    effect->procId = procId;
+    effect->state = PREPROC_EFFECT_STATE_INIT;
+    return 0;
+}
+
+int Effect_Create(preproc_effect_t *effect,
+               preproc_session_t *session,
+               effect_handle_t  *interface)
+{
+    effect->session = session;
+    *interface = (effect_handle_t)&effect->itfe;
+    return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
+}
+
+int Effect_Release(preproc_effect_t *effect)
+{
+    return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
+}
+
+
+//------------------------------------------------------------------------------
+// Session functions
+//------------------------------------------------------------------------------
+
+#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
+
+static const int kPreprocDefaultSr = 16000;
+static const int kPreProcDefaultCnl = 1;
+
+int Session_Init(preproc_session_t *session)
+{
+    size_t i;
+    int status = 0;
+
+    session->state = PREPROC_SESSION_STATE_INIT;
+    session->id = 0;
+    session->io = 0;
+    session->createdMsk = 0;
+    session->apm = NULL;
+    for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
+        status = Effect_Init(&session->effects[i], i);
+    }
+    return status;
+}
+
+
+extern "C" int Session_CreateEffect(preproc_session_t *session,
+                                    int32_t procId,
+                                    effect_handle_t  *interface)
+{
+    int status = -ENOMEM;
+
+    LOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
+
+    if (session->createdMsk == 0) {
+        session->apm = webrtc::AudioProcessing::Create(session->io);
+        if (session->apm == NULL) {
+            LOGW("Session_CreateEffect could not get apm engine");
+            goto error;
+        }
+        session->apm->set_sample_rate_hz(kPreprocDefaultSr);
+        session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
+        session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
+        session->procFrame = new webrtc::AudioFrame();
+        if (session->procFrame == NULL) {
+            LOGW("Session_CreateEffect could not allocate audio frame");
+            goto error;
+        }
+        session->revFrame = new webrtc::AudioFrame();
+        if (session->revFrame == NULL) {
+            LOGW("Session_CreateEffect could not allocate reverse audio frame");
+            goto error;
+        }
+        session->apmSamplingRate = kPreprocDefaultSr;
+        session->apmFrameCount = (kPreprocDefaultSr) / 100;
+        session->frameCount = session->apmFrameCount;
+        session->samplingRate = kPreprocDefaultSr;
+        session->inChannelCount = kPreProcDefaultCnl;
+        session->outChannelCount = kPreProcDefaultCnl;
+        session->procFrame->_frequencyInHz = kPreprocDefaultSr;
+        session->procFrame->_audioChannel = kPreProcDefaultCnl;
+        session->revChannelCount = kPreProcDefaultCnl;
+        session->revFrame->_frequencyInHz = kPreprocDefaultSr;
+        session->revFrame->_audioChannel = kPreProcDefaultCnl;
+        session->enabledMsk = 0;
+        session->processedMsk = 0;
+        session->revEnabledMsk = 0;
+        session->revProcessedMsk = 0;
+        session->inResampler = NULL;
+        session->inBuf = NULL;
+        session->inBufSize = 0;
+        session->outResampler = NULL;
+        session->outBuf = NULL;
+        session->outBufSize = 0;
+        session->revResampler = NULL;
+        session->revBuf = NULL;
+        session->revBufSize = 0;
+    }
+    status = Effect_Create(&session->effects[procId], session, interface);
+    if (status < 0) {
+        goto error;
+    }
+    LOGV("Session_CreateEffect OK");
+    session->createdMsk |= (1<<procId);
+    return status;
+
+error:
+    if (session->createdMsk == 0) {
+        delete session->revFrame;
+        session->revFrame = NULL;
+        delete session->procFrame;
+        session->procFrame = NULL;
+        webrtc::AudioProcessing::Destroy(session->apm);
+        session->apm = NULL;
+    }
+    return status;
+}
+
+int Session_ReleaseEffect(preproc_session_t *session,
+                          preproc_effect_t *fx)
+{
+    LOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
+    session->createdMsk &= ~(1<<fx->procId);
+    if (session->createdMsk == 0) {
+        webrtc::AudioProcessing::Destroy(session->apm);
+        session->apm = NULL;
+        delete session->procFrame;
+        session->procFrame = NULL;
+        delete session->revFrame;
+        session->revFrame = NULL;
+        if (session->inResampler != NULL) {
+            speex_resampler_destroy(session->inResampler);
+            session->inResampler = NULL;
+        }
+        if (session->outResampler != NULL) {
+            speex_resampler_destroy(session->outResampler);
+            session->outResampler = NULL;
+        }
+        if (session->revResampler != NULL) {
+            speex_resampler_destroy(session->revResampler);
+            session->revResampler = NULL;
+        }
+        delete session->inBuf;
+        session->inBuf = NULL;
+        delete session->outBuf;
+        session->outBuf = NULL;
+        delete session->revBuf;
+        session->revBuf = NULL;
+
+        session->io = 0;
+    }
+
+    return 0;
+}
+
+
+int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
+{
+    uint32_t sr;
+    uint32_t inCnl = popcount(config->inputCfg.channels);
+    uint32_t outCnl = popcount(config->outputCfg.channels);
+
+    if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
+        config->inputCfg.format != config->outputCfg.format ||
+        config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+        return -EINVAL;
+    }
+
+    LOGV("Session_SetConfig sr %d cnl %08x",
+         config->inputCfg.samplingRate, config->inputCfg.channels);
+    int status;
+
+    // AEC implementation is limited to 16kHz
+    if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
+        session->apmSamplingRate = 32000;
+    } else
+    if (config->inputCfg.samplingRate >= 16000) {
+        session->apmSamplingRate = 16000;
+    } else if (config->inputCfg.samplingRate >= 8000) {
+        session->apmSamplingRate = 8000;
+    }
+    status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
+    if (status < 0) {
+        return -EINVAL;
+    }
+    status = session->apm->set_num_channels(inCnl, outCnl);
+    if (status < 0) {
+        return -EINVAL;
+    }
+    status = session->apm->set_num_reverse_channels(inCnl);
+    if (status < 0) {
+        return -EINVAL;
+    }
+
+    session->samplingRate = config->inputCfg.samplingRate;
+    session->apmFrameCount = session->apmSamplingRate / 100;
+    if (session->samplingRate == session->apmSamplingRate) {
+        session->frameCount = session->apmFrameCount;
+    } else {
+        session->frameCount = (session->apmFrameCount * session->samplingRate) /
+                session->apmSamplingRate  + 1;
+    }
+    session->inChannelCount = inCnl;
+    session->outChannelCount = outCnl;
+    session->procFrame->_audioChannel = inCnl;
+    session->procFrame->_frequencyInHz = session->apmSamplingRate;
+
+    session->revChannelCount = inCnl;
+    session->revFrame->_audioChannel = inCnl;
+    session->revFrame->_frequencyInHz = session->apmSamplingRate;
+
+    if (session->inResampler != NULL) {
+        speex_resampler_destroy(session->inResampler);
+        session->inResampler = NULL;
+    }
+    if (session->outResampler != NULL) {
+        speex_resampler_destroy(session->outResampler);
+        session->outResampler = NULL;
+    }
+    if (session->revResampler != NULL) {
+        speex_resampler_destroy(session->revResampler);
+        session->revResampler = NULL;
+    }
+    if (session->samplingRate != session->apmSamplingRate) {
+        int error;
+        session->inResampler = speex_resampler_init(session->inChannelCount,
+                                                    session->samplingRate,
+                                                    session->apmSamplingRate,
+                                                    RESAMPLER_QUALITY,
+                                                    &error);
+        if (session->inResampler == NULL) {
+            LOGW("Session_SetConfig Cannot create speex resampler: %s",
+                 speex_resampler_strerror(error));
+            return -EINVAL;
+        }
+        session->outResampler = speex_resampler_init(session->outChannelCount,
+                                                    session->apmSamplingRate,
+                                                    session->samplingRate,
+                                                    RESAMPLER_QUALITY,
+                                                    &error);
+        if (session->outResampler == NULL) {
+            LOGW("Session_SetConfig Cannot create speex resampler: %s",
+                 speex_resampler_strerror(error));
+            speex_resampler_destroy(session->inResampler);
+            session->inResampler = NULL;
+            return -EINVAL;
+        }
+        session->revResampler = speex_resampler_init(session->inChannelCount,
+                                                    session->samplingRate,
+                                                    session->apmSamplingRate,
+                                                    RESAMPLER_QUALITY,
+                                                    &error);
+        if (session->revResampler == NULL) {
+            LOGW("Session_SetConfig Cannot create speex resampler: %s",
+                 speex_resampler_strerror(error));
+            speex_resampler_destroy(session->inResampler);
+            session->inResampler = NULL;
+            speex_resampler_destroy(session->outResampler);
+            session->outResampler = NULL;
+            return -EINVAL;
+        }
+    }
+
+    session->state = PREPROC_SESSION_STATE_CONFIG;
+    return 0;
+}
+
+int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
+{
+    if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
+            config->inputCfg.format != config->outputCfg.format ||
+            config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+        return -EINVAL;
+    }
+
+    LOGV("Session_SetReverseConfig sr %d cnl %08x",
+         config->inputCfg.samplingRate, config->inputCfg.channels);
+
+    if (session->state < PREPROC_SESSION_STATE_CONFIG) {
+        return -ENOSYS;
+    }
+    if (config->inputCfg.samplingRate != session->samplingRate ||
+            config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+        return -EINVAL;
+    }
+    uint32_t inCnl = popcount(config->inputCfg.channels);
+    int status = session->apm->set_num_reverse_channels(inCnl);
+    if (status < 0) {
+        return -EINVAL;
+    }
+    session->revChannelCount = inCnl;
+    session->revFrame->_audioChannel = inCnl;
+    session->revFrame->_frequencyInHz = session->apmSamplingRate;
+    return 0;
+}
+
+void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
+{
+    if (enabled) {
+        if(session->enabledMsk == 0) {
+            session->framesIn = 0;
+            if (session->inResampler != NULL) {
+                speex_resampler_reset_mem(session->inResampler);
+            }
+            session->framesOut = 0;
+            if (session->outResampler != NULL) {
+                speex_resampler_reset_mem(session->outResampler);
+            }
+        }
+        session->enabledMsk |= (1 << procId);
+        if (HasReverseStream(procId)) {
+            session->framesRev = 0;
+            if (session->revResampler != NULL) {
+                speex_resampler_reset_mem(session->revResampler);
+            }
+            session->revEnabledMsk |= (1 << procId);
+        }
+    } else {
+        session->enabledMsk &= ~(1 << procId);
+        if (HasReverseStream(procId)) {
+            session->revEnabledMsk &= ~(1 << procId);
+        }
+    }
+    LOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
+         procId, enabled, session->enabledMsk, session->revEnabledMsk);
+    session->processedMsk = 0;
+    if (HasReverseStream(procId)) {
+        session->revProcessedMsk = 0;
+    }
+}
+
+//------------------------------------------------------------------------------
+// Bundle functions
+//------------------------------------------------------------------------------
+
+static int sInitStatus = 1;
+static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
+
+preproc_session_t *PreProc_GetSession(int32_t procId, int32_t  sessionId, int32_t  ioId)
+{
+    size_t i;
+    int free = -1;
+    for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
+        if (sSessions[i].io == ioId) {
+            if (sSessions[i].createdMsk & (1 << procId)) {
+                return NULL;
+            }
+            return &sSessions[i];
+        }
+    }
+    for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
+        if (sSessions[i].io == 0) {
+            sSessions[i].id = sessionId;
+            sSessions[i].io = ioId;
+            return &sSessions[i];
+        }
+    }
+    return NULL;
+}
+
+
+int PreProc_Init() {
+    size_t i;
+    int status = 0;
+
+    if (sInitStatus <= 0) {
+        return sInitStatus;
+    }
+    for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
+        status = Session_Init(&sSessions[i]);
+    }
+    sInitStatus = status;
+    return sInitStatus;
+}
+
+const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
+{
+    size_t i;
+    for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
+        if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
+            return sDescriptors[i];
+        }
+    }
+    return NULL;
+}
+
+
+extern "C" {
+
+//------------------------------------------------------------------------------
+// Effect Control Interface Implementation
+//------------------------------------------------------------------------------
+
+int PreProcessingFx_Process(effect_handle_t     self,
+                            audio_buffer_t    *inBuffer,
+                            audio_buffer_t    *outBuffer)
+{
+    preproc_effect_t * effect = (preproc_effect_t *)self;
+    int    status = 0;
+
+    if (effect == NULL){
+        LOGV("PreProcessingFx_Process() ERROR effect == NULL");
+        return -EINVAL;
+    }
+    preproc_session_t * session = (preproc_session_t *)effect->session;
+
+    if (inBuffer == NULL  || inBuffer->raw == NULL  ||
+            outBuffer == NULL || outBuffer->raw == NULL){
+        LOGW("PreProcessingFx_Process() ERROR bad pointer");
+        return -EINVAL;
+    }
+
+    session->processedMsk |= (1<<effect->procId);
+
+//    LOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
+//         inBuffer->frameCount, session->enabledMsk, session->processedMsk);
+
+    if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
+        effect->session->processedMsk = 0;
+        size_t framesRq = outBuffer->frameCount;
+        size_t framesWr = 0;
+        if (session->framesOut) {
+            size_t fr = session->framesOut;
+            if (outBuffer->frameCount < fr) {
+                fr = outBuffer->frameCount;
+            }
+            memcpy(outBuffer->s16,
+                  session->outBuf,
+                  fr * session->outChannelCount * sizeof(int16_t));
+            memcpy(session->outBuf,
+                  session->outBuf + fr * session->outChannelCount,
+                  (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
+            session->framesOut -= fr;
+            framesWr += fr;
+        }
+        outBuffer->frameCount = framesWr;
+        if (framesWr == framesRq) {
+            inBuffer->frameCount = 0;
+            return 0;
+        }
+
+        if (session->inResampler != NULL) {
+            size_t fr = session->frameCount - session->framesIn;
+            if (inBuffer->frameCount < fr) {
+                fr = inBuffer->frameCount;
+            }
+            if (session->inBufSize < session->framesIn + fr) {
+                session->inBufSize = session->framesIn + fr;
+                session->inBuf = (int16_t *)realloc(session->inBuf,
+                                 session->inBufSize * session->inChannelCount * sizeof(int16_t));
+            }
+            memcpy(session->inBuf + session->framesIn * session->inChannelCount,
+                   inBuffer->s16,
+                   fr * session->inChannelCount * sizeof(int16_t));
+
+            session->framesIn += fr;
+            inBuffer->frameCount = fr;
+            if (session->framesIn < session->frameCount) {
+                return 0;
+            }
+            size_t frIn = session->framesIn;
+            size_t frOut = session->apmFrameCount;
+            if (session->inChannelCount == 1) {
+                speex_resampler_process_int(session->inResampler,
+                                            0,
+                                            session->inBuf,
+                                            &frIn,
+                                            session->procFrame->_payloadData,
+                                            &frOut);
+            } else {
+                speex_resampler_process_interleaved_int(session->inResampler,
+                                                        session->inBuf,
+                                                        &frIn,
+                                                        session->procFrame->_payloadData,
+                                                        &frOut);
+            }
+            memcpy(session->inBuf,
+                   session->inBuf + frIn * session->inChannelCount,
+                   (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
+            session->framesIn -= frIn;
+        } else {
+            size_t fr = session->frameCount - session->framesIn;
+            if (inBuffer->frameCount < fr) {
+                fr = inBuffer->frameCount;
+            }
+            memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
+                   inBuffer->s16,
+                   fr * session->inChannelCount * sizeof(int16_t));
+            session->framesIn += fr;
+            inBuffer->frameCount = fr;
+            if (session->framesIn < session->frameCount) {
+                return 0;
+            }
+            session->framesIn = 0;
+        }
+        session->procFrame->_payloadDataLengthInSamples =
+                session->apmFrameCount * session->inChannelCount;
+
+        effect->session->apm->ProcessStream(session->procFrame);
+
+        if (session->outBufSize < session->framesOut + session->frameCount) {
+            session->outBufSize = session->framesOut + session->frameCount;
+            session->outBuf = (int16_t *)realloc(session->outBuf,
+                              session->outBufSize * session->outChannelCount * sizeof(int16_t));
+        }
+
+        if (session->outResampler != NULL) {
+            size_t frIn = session->apmFrameCount;
+            size_t frOut = session->frameCount;
+            if (session->inChannelCount == 1) {
+                speex_resampler_process_int(session->outResampler,
+                                    0,
+                                    session->procFrame->_payloadData,
+                                    &frIn,
+                                    session->outBuf + session->framesOut * session->outChannelCount,
+                                    &frOut);
+            } else {
+                speex_resampler_process_interleaved_int(session->outResampler,
+                                    session->procFrame->_payloadData,
+                                    &frIn,
+                                    session->outBuf + session->framesOut * session->outChannelCount,
+                                    &frOut);
+            }
+            session->framesOut += frOut;
+        } else {
+            memcpy(session->outBuf + session->framesOut * session->outChannelCount,
+                   session->procFrame->_payloadData,
+                   session->frameCount * session->outChannelCount * sizeof(int16_t));
+            session->framesOut += session->frameCount;
+        }
+        size_t fr = session->framesOut;
+        if (framesRq - framesWr < fr) {
+            fr = framesRq - framesWr;
+        }
+        memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
+              session->outBuf,
+              fr * session->outChannelCount * sizeof(int16_t));
+        memcpy(session->outBuf,
+              session->outBuf + fr * session->outChannelCount,
+              (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
+        session->framesOut -= fr;
+        outBuffer->frameCount += fr;
+
+        return 0;
+    } else {
+        return -ENODATA;
+    }
+}
+
+int PreProcessingFx_Command(effect_handle_t  self,
+                            uint32_t            cmdCode,
+                            uint32_t            cmdSize,
+                            void                *pCmdData,
+                            uint32_t            *replySize,
+                            void                *pReplyData)
+{
+    preproc_effect_t * effect = (preproc_effect_t *) self;
+    int retsize;
+    int status;
+
+    if (effect == NULL){
+        return -EINVAL;
+    }
+
+    //LOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
+
+    switch (cmdCode){
+        case EFFECT_CMD_INIT:
+            if (pReplyData == NULL || *replySize != sizeof(int)){
+                return -EINVAL;
+            }
+            if (effect->ops->init) {
+                effect->ops->init(effect);
+            }
+            *(int *)pReplyData = 0;
+            break;
+
+        case EFFECT_CMD_CONFIGURE:
+            if (pCmdData    == NULL||
+                cmdSize     != sizeof(effect_config_t)||
+                pReplyData  == NULL||
+                *replySize  != sizeof(int)){
+                LOGV("PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_CONFIGURE: ERROR");
+                return -EINVAL;
+            }
+            *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
+            if (*(int *)pReplyData != 0) {
+                break;
+            }
+            *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+            break;
+
+        case EFFECT_CMD_CONFIGURE_REVERSE:
+            if (pCmdData    == NULL||
+                cmdSize     != sizeof(effect_config_t)||
+                pReplyData  == NULL||
+                *replySize  != sizeof(int)){
+                LOGV("PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_CONFIGURE_REVERSE: ERROR");
+                return -EINVAL;
+            }
+            *(int *)pReplyData = Session_SetReverseConfig(effect->session,
+                                                          (effect_config_t *)pCmdData);
+            if (*(int *)pReplyData != 0) {
+                break;
+            }
+            break;
+
+        case EFFECT_CMD_RESET:
+            if (effect->ops->reset) {
+                effect->ops->reset(effect);
+            }
+            break;
+
+        case EFFECT_CMD_GET_PARAM:{
+            if (pCmdData == NULL ||
+                    cmdSize < (int)sizeof(effect_param_t) ||
+                    pReplyData == NULL ||
+                    *replySize < (int)sizeof(effect_param_t)){
+                LOGV("PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_GET_PARAM: ERROR");
+                return -EINVAL;
+            }
+            effect_param_t *p = (effect_param_t *)pCmdData;
+
+            memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
+
+            p = (effect_param_t *)pReplyData;
+
+            int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+
+            if (effect->ops->get_parameter) {
+                p->status = effect->ops->get_parameter(effect, p->data,
+                                                       (size_t  *)&p->vsize,
+                                                       p->data + voffset);
+                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
+            }
+        } break;
+
+        case EFFECT_CMD_SET_PARAM:{
+            if (pCmdData == NULL||
+                    cmdSize < (int)sizeof(effect_param_t) ||
+                    pReplyData == NULL ||
+                    *replySize != sizeof(int32_t)){
+                LOGV("PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_SET_PARAM: ERROR");
+                return -EINVAL;
+            }
+            effect_param_t *p = (effect_param_t *) pCmdData;
+
+            if (p->psize != sizeof(int32_t)){
+                LOGV("PreProcessingFx_Command cmdCode Case: "
+                        "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
+                return -EINVAL;
+            }
+            if (effect->ops->set_parameter) {
+                *(int *)pReplyData = effect->ops->set_parameter(effect,
+                                                                (void *)p->data,
+                                                                p->data + p->psize);
+            }
+        } break;
+
+        case EFFECT_CMD_ENABLE:
+            if (pReplyData == NULL || *replySize != sizeof(int)){
+                LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
+                return -EINVAL;
+            }
+            *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
+            break;
+
+        case EFFECT_CMD_DISABLE:
+            if (pReplyData == NULL || *replySize != sizeof(int)){
+                LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
+                return -EINVAL;
+            }
+            *(int *)pReplyData  = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+            break;
+
+        case EFFECT_CMD_SET_DEVICE:
+        case EFFECT_CMD_SET_INPUT_DEVICE:
+            if (pCmdData == NULL ||
+                cmdSize != sizeof(uint32_t)) {
+                LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
+                return -EINVAL;
+            }
+
+            if (effect->ops->set_device) {
+                effect->ops->set_device(effect, *(uint32_t *)pCmdData);
+            }
+            break;
+
+        case EFFECT_CMD_SET_VOLUME:
+        case EFFECT_CMD_SET_AUDIO_MODE:
+            break;
+
+        default:
+            return -EINVAL;
+    }
+    return 0;
+}
+
+
+int PreProcessingFx_GetDescriptor(effect_handle_t   self,
+                                  effect_descriptor_t *pDescriptor)
+{
+    preproc_effect_t * effect = (preproc_effect_t *) self;
+
+    if (effect == NULL || pDescriptor == NULL) {
+        return -EINVAL;
+    }
+
+    memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
+
+    return 0;
+}
+
+int PreProcessingFx_ProcessReverse(effect_handle_t     self,
+                                   audio_buffer_t    *inBuffer,
+                                   audio_buffer_t    *outBuffer)
+{
+    preproc_effect_t * effect = (preproc_effect_t *)self;
+    int    status = 0;
+
+    if (effect == NULL){
+        LOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
+        return -EINVAL;
+    }
+    preproc_session_t * session = (preproc_session_t *)effect->session;
+
+    if (inBuffer == NULL  || inBuffer->raw == NULL){
+        LOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
+        return -EINVAL;
+    }
+
+    session->revProcessedMsk |= (1<<effect->procId);
+
+//    LOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
+//         inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
+
+
+    if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
+        effect->session->revProcessedMsk = 0;
+        if (session->revResampler != NULL) {
+            size_t fr = session->frameCount - session->framesRev;
+            if (inBuffer->frameCount < fr) {
+                fr = inBuffer->frameCount;
+            }
+            if (session->revBufSize < session->framesRev + fr) {
+                session->revBufSize = session->framesRev + fr;
+                session->revBuf = (int16_t *)realloc(session->revBuf,
+                                  session->revBufSize * session->inChannelCount * sizeof(int16_t));
+            }
+            memcpy(session->revBuf + session->framesRev * session->inChannelCount,
+                   inBuffer->s16,
+                   fr * session->inChannelCount * sizeof(int16_t));
+
+            session->framesRev += fr;
+            inBuffer->frameCount = fr;
+            if (session->framesRev < session->frameCount) {
+                return 0;
+            }
+            size_t frIn = session->framesRev;
+            size_t frOut = session->apmFrameCount;
+            if (session->inChannelCount == 1) {
+                speex_resampler_process_int(session->revResampler,
+                                            0,
+                                            session->revBuf,
+                                            &frIn,
+                                            session->revFrame->_payloadData,
+                                            &frOut);
+            } else {
+                speex_resampler_process_interleaved_int(session->revResampler,
+                                                        session->revBuf,
+                                                        &frIn,
+                                                        session->revFrame->_payloadData,
+                                                        &frOut);
+            }
+            memcpy(session->revBuf,
+                   session->revBuf + frIn * session->inChannelCount,
+                   (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
+            session->framesRev -= frIn;
+        } else {
+            size_t fr = session->frameCount - session->framesRev;
+            if (inBuffer->frameCount < fr) {
+                fr = inBuffer->frameCount;
+            }
+            memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
+                   inBuffer->s16,
+                   fr * session->inChannelCount * sizeof(int16_t));
+            session->framesRev += fr;
+            inBuffer->frameCount = fr;
+            if (session->framesRev < session->frameCount) {
+                return 0;
+            }
+            session->framesRev = 0;
+        }
+        session->revFrame->_payloadDataLengthInSamples =
+                session->apmFrameCount * session->inChannelCount;
+        effect->session->apm->AnalyzeReverseStream(session->revFrame);
+        return 0;
+    } else {
+        return -ENODATA;
+    }
+}
+
+
+// effect_handle_t interface implementation for effect
+const struct effect_interface_s sEffectInterface = {
+    PreProcessingFx_Process,
+    PreProcessingFx_Command,
+    PreProcessingFx_GetDescriptor,
+    NULL
+};
+
+const struct effect_interface_s sEffectInterfaceReverse = {
+    PreProcessingFx_Process,
+    PreProcessingFx_Command,
+    PreProcessingFx_GetDescriptor,
+    PreProcessingFx_ProcessReverse
+};
+
+//------------------------------------------------------------------------------
+// Effect Library Interface Implementation
+//------------------------------------------------------------------------------
+
+int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
+{
+    if (PreProc_Init() != 0) {
+        return sInitStatus;
+    }
+    if (pNumEffects == NULL) {
+        return -EINVAL;
+    }
+    *pNumEffects = PREPROC_NUM_EFFECTS;
+    return sInitStatus;
+}
+
+int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
+{
+    if (PreProc_Init() != 0) {
+        return sInitStatus;
+    }
+    if (index >= PREPROC_NUM_EFFECTS) {
+        return -EINVAL;
+    }
+    memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
+    return 0;
+}
+
+int PreProcessingLib_Create(effect_uuid_t       *uuid,
+                            int32_t             sessionId,
+                            int32_t             ioId,
+                            effect_handle_t  *pInterface)
+{
+    LOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
+
+    int status;
+    const effect_descriptor_t *desc;
+    preproc_session_t *session;
+    uint32_t procId;
+
+    if (PreProc_Init() != 0) {
+        return sInitStatus;
+    }
+    desc =  PreProc_GetDescriptor(uuid);
+    if (desc == NULL) {
+        LOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
+        return -EINVAL;
+    }
+    procId = UuidToProcId(&desc->type);
+
+    session = PreProc_GetSession(procId, sessionId, ioId);
+    if (session == NULL) {
+        LOGW("EffectCreate: no more session available");
+        return -EINVAL;
+    }
+
+    status = Session_CreateEffect(session, procId, pInterface);
+
+    if (status < 0 && session->createdMsk == 0) {
+        session->io = 0;
+    }
+    return status;
+}
+
+int PreProcessingLib_Release(effect_handle_t interface)
+{
+    int status;
+    LOGV("EffectRelease start %p", interface);
+    if (PreProc_Init() != 0) {
+        return sInitStatus;
+    }
+
+    preproc_effect_t *fx = (preproc_effect_t *)interface;
+
+    if (fx->session->io == 0) {
+        return -EINVAL;
+    }
+    return Session_ReleaseEffect(fx->session, fx);
+}
+
+int PreProcessingLib_GetDescriptor(effect_uuid_t       *uuid,
+                                   effect_descriptor_t *pDescriptor) {
+
+    if (pDescriptor == NULL || uuid == NULL){
+        return -EINVAL;
+    }
+
+    const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
+    if (desc == NULL) {
+        LOGV("PreProcessingLib_GetDescriptor() not found");
+        return  -EINVAL;
+    }
+
+    LOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
+
+    memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+    return 0;
+}
+
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+    tag : AUDIO_EFFECT_LIBRARY_TAG,
+    version : EFFECT_LIBRARY_API_VERSION,
+    name : "Audio Preprocessing Library",
+    implementor : "The Android Open Source Project",
+    query_num_effects : PreProcessingLib_QueryNumberEffects,
+    query_effect : PreProcessingLib_QueryEffect,
+    create_effect : PreProcessingLib_Create,
+    release_effect : PreProcessingLib_Release,
+    get_descriptor : PreProcessingLib_GetDescriptor
+};
+
+}; // extern "C"
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/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 5a5330d..0251baf 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -58,8 +58,10 @@
 }
 
 NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
-    mLiveSession->disconnect();
-    mLiveLooper->stop();
+    if (mLiveSession != NULL) {
+        mLiveSession->disconnect();
+        mLiveLooper->stop();
+    }
 }
 
 void NuPlayer::HTTPLiveSource::start() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7cd8b6c..c6fca2c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -118,9 +118,15 @@
             mPlayer->start();
 
             if (mStartupSeekTimeUs >= 0) {
-                mPlayer->seekToAsync(mStartupSeekTimeUs);
+                if (mStartupSeekTimeUs == 0) {
+                    notifySeekComplete();
+                } else {
+                    mPlayer->seekToAsync(mStartupSeekTimeUs);
+                }
+
                 mStartupSeekTimeUs = -1;
             }
+
             break;
         }
         case PLAYING:
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 5cab60e..4f8336e 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -4330,26 +4330,19 @@
 
 status_t QueryCodecs(
         const sp<IOMX> &omx,
-        const char *mime, bool queryDecoders,
+        const char *mime, bool queryDecoders, bool hwCodecOnly,
         Vector<CodecCapabilities> *results) {
+    Vector<String8> matchingCodecs;
     results->clear();
 
-    for (int index = 0;; ++index) {
-        const char *componentName;
+    OMXCodec::findMatchingCodecs(mime,
+            !queryDecoders /*createEncoder*/,
+            NULL /*matchComponentName*/,
+            hwCodecOnly ? OMXCodec::kHardwareCodecsOnly : 0 /*flags*/,
+            &matchingCodecs);
 
-        if (!queryDecoders) {
-            componentName = GetCodec(
-                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
-                    mime, index);
-        } else {
-            componentName = GetCodec(
-                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
-                    mime, index);
-        }
-
-        if (!componentName) {
-            return OK;
-        }
+    for (size_t c = 0; c < matchingCodecs.size(); c++) {
+        const char *componentName = matchingCodecs.itemAt(c).string();
 
         if (strncmp(componentName, "OMX.", 4)) {
             // Not an OpenMax component but a software codec.
@@ -4411,6 +4404,8 @@
 
         CHECK_EQ(omx->freeNode(node), (status_t)OK);
     }
+
+    return OK;
 }
 
 void OMXCodec::restorePatchedDataPointer(BufferInfo *info) {
diff --git a/media/libstagefright/codecs/aacenc/src/bit_cnt.c b/media/libstagefright/codecs/aacenc/src/bit_cnt.c
index dd0b9b4..8853efc 100644
--- a/media/libstagefright/codecs/aacenc/src/bit_cnt.c
+++ b/media/libstagefright/codecs/aacenc/src/bit_cnt.c
@@ -496,7 +496,7 @@
 {
 
   Word32 i, t0, t1, t2, t3, t00, t01;
-  Word16 codeWord, codeLength;
+  UWord16 codeWord, codeLength;
   Word16 sign, signLength;
 
    
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/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index ca61b3d..73b3d5b 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -494,6 +494,12 @@
 
         bool firstTime = (mPlaylist == NULL);
 
+        if ((ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
+            // If we switch bandwidths, do not pay any heed to whether
+            // playlists changed since the last time...
+            mPlaylist.clear();
+        }
+
         bool unchanged;
         sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged);
         if (playlist == NULL) {
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 817eac05..20225ba 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -345,56 +345,28 @@
 
 #ifdef MTP_DEVICE 
 int MtpDataPacket::read(int fd) {
-    // first read the header
-    int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
-    if (ret != MTP_CONTAINER_HEADER_SIZE)
+    int ret = ::read(fd, mBuffer, mBufferSize);
+    if (ret < MTP_CONTAINER_HEADER_SIZE)
         return -1;
-    // then the following data
-    int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
-    allocate(total);
-    int remaining = total - MTP_CONTAINER_HEADER_SIZE;
-    ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
-    if (ret != remaining)
-        return -1;
-
-    mPacketSize = total;
+    mPacketSize = ret;
     mOffset = MTP_CONTAINER_HEADER_SIZE;
-    return total;
-}
-
-int MtpDataPacket::readDataHeader(int fd) {
-    int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
-    if (ret > 0)
-        mPacketSize = ret;
-    else
-        mPacketSize = 0;
     return ret;
 }
 
 int MtpDataPacket::write(int fd) {
     MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
     MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    // send header separately from data
-    int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
-    if (ret == MTP_CONTAINER_HEADER_SIZE)
-        ret = ::write(fd, mBuffer + MTP_CONTAINER_HEADER_SIZE,
-                        mPacketSize - MTP_CONTAINER_HEADER_SIZE);
-    return (ret < 0 ? ret : 0);
-}
-
-int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
-    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
-    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+    int ret = ::write(fd, mBuffer, mPacketSize);
     return (ret < 0 ? ret : 0);
 }
 
 int MtpDataPacket::writeData(int fd, void* data, uint32_t length) {
-    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length + MTP_CONTAINER_HEADER_SIZE);
+    allocate(length);
+    memcpy(mBuffer + MTP_CONTAINER_HEADER_SIZE, data, length);
+    length += MTP_CONTAINER_HEADER_SIZE;
+    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
     MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
-    if (ret == MTP_CONTAINER_HEADER_SIZE)
-        ret = ::write(fd, data, length);
+    int ret = ::write(fd, mBuffer, length);
     return (ret < 0 ? ret : 0);
 }
 
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 8a08948..2b81063 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -41,6 +41,7 @@
     void                setOperationCode(MtpOperationCode code);
     void                setTransactionID(MtpTransactionID id);
 
+    inline const uint8_t*     getData() const { return mBuffer + MTP_CONTAINER_HEADER_SIZE; }
     inline uint8_t      getUInt8() { return (uint8_t)mBuffer[mOffset++]; }
     inline int8_t       getInt8() { return (int8_t)mBuffer[mOffset++]; }
     uint16_t            getUInt16();
@@ -95,11 +96,9 @@
 #ifdef MTP_DEVICE
     // fill our buffer with data from the given file descriptor
     int                 read(int fd);
-    int                 readDataHeader(int fd);
 
     // write our data to the given file descriptor
     int                 write(int fd);
-    int                 writeDataHeader(int fd, uint32_t length);
     int                 writeData(int fd, void* data, uint32_t length);
 #endif
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 4047e2e..a9b539b 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -731,14 +731,12 @@
     }
     mfr.offset = 0;
     mfr.length = fileLength;
-
-    // send data header
-    mData.setOperationCode(mRequest.getOperationCode());
-    mData.setTransactionID(mRequest.getTransactionID());
-    mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
+    mfr.command = mRequest.getOperationCode();
+    mfr.transaction_id = mRequest.getTransactionID();
 
     // then transfer the file
-    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+    LOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
     close(mfr.fd);
     if (ret < 0) {
         if (errno == ECANCELED)
@@ -798,15 +796,13 @@
     }
     mfr.offset = offset;
     mfr.length = length;
+    mfr.command = mRequest.getOperationCode();
+    mfr.transaction_id = mRequest.getTransactionID();
     mResponse.setParameter(1, length);
 
-    // send data header
-    mData.setOperationCode(mRequest.getOperationCode());
-    mData.setTransactionID(mRequest.getTransactionID());
-    mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
-
-    // then transfer the file
-    int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+    // transfer the file
+    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+    LOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
     close(mfr.fd);
     if (ret < 0) {
         if (errno == ECANCELED)
@@ -918,7 +914,7 @@
         return MTP_RESPONSE_GENERAL_ERROR;
     MtpResponseCode result = MTP_RESPONSE_OK;
     mode_t mask;
-    int ret;
+    int ret, initialData;
 
     if (mSendObjectHandle == kInvalidObjectHandle) {
         LOGE("Expected SendObjectInfo before SendObject");
@@ -926,12 +922,13 @@
         goto done;
     }
 
-    // read the header
-    ret = mData.readDataHeader(mFD);
-    // FIXME - check for errors here.
-
-    // reset so we don't attempt to send this back
-    mData.reset();
+    // read the header, and possibly some data
+    ret = mData.read(mFD);
+    if (ret < MTP_CONTAINER_HEADER_SIZE) {
+        result = MTP_RESPONSE_GENERAL_ERROR;
+        goto done;
+    }
+    initialData = ret - MTP_CONTAINER_HEADER_SIZE;
 
     mtp_file_range  mfr;
     mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
@@ -945,16 +942,20 @@
     fchmod(mfr.fd, mFilePermission);
     umask(mask);
 
-    mfr.offset = 0;
-    mfr.length = mSendObjectFileSize;
+    if (initialData > 0)
+        ret = write(mfr.fd, mData.getData(), initialData);
 
-    LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
-    // transfer the file
-    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+    if (mSendObjectFileSize - initialData > 0) {
+        mfr.offset = initialData;
+        mfr.length = mSendObjectFileSize - initialData;
+
+        LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
+        // transfer the file
+        ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+        LOGV("MTP_RECEIVE_FILE returned %d\n", ret);
+    }
     close(mfr.fd);
 
-    LOGV("MTP_RECEIVE_FILE returned %d", ret);
-
     if (ret < 0) {
         unlink(mSendObjectFilePath);
         if (errno == ECANCELED)
@@ -964,6 +965,9 @@
     }
 
 done:
+    // reset so we don't attempt to send the data back
+    mData.reset();
+
     mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
             result == MTP_RESPONSE_OK);
     mSendObjectHandle = kInvalidObjectHandle;
@@ -1096,23 +1100,31 @@
         return MTP_RESPONSE_GENERAL_ERROR;
     }
 
-    // read the header
-    int ret = mData.readDataHeader(mFD);
-    // FIXME - check for errors here.
-
-    // reset so we don't attempt to send this back
-    mData.reset();
-
     const char* filePath = (const char *)edit->mPath;
-    LOGV("receiving partial %s %lld %ld\n", filePath, offset, length);
-    mtp_file_range  mfr;
-    mfr.fd = edit->mFD;
-    mfr.offset = offset;
-    mfr.length = length;
+    LOGV("receiving partial %s %lld %lld\n", filePath, offset, length);
 
-    // transfer the file
-    ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
-    LOGV("MTP_RECEIVE_FILE returned %d", ret);
+    // read the header, and possibly some data
+    int ret = mData.read(mFD);
+    if (ret < MTP_CONTAINER_HEADER_SIZE)
+        return MTP_RESPONSE_GENERAL_ERROR;
+    int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
+
+    if (initialData > 0) {
+        ret = write(edit->mFD, mData.getData(), initialData);
+        offset += initialData;
+        length -= initialData;
+    }
+
+    if (length > 0) {
+        mtp_file_range  mfr;
+        mfr.fd = edit->mFD;
+        mfr.offset = offset;
+        mfr.length = length;
+
+        // transfer the file
+        ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+        LOGV("MTP_RECEIVE_FILE returned %d", ret);
+    }
     if (ret < 0) {
         mResponse.setParameter(1, 0);
         if (errno == ECANCELED)
@@ -1120,6 +1132,9 @@
         else
             return MTP_RESPONSE_GENERAL_ERROR;
     }
+
+    // reset so we don't attempt to send this back
+    mData.reset();
     mResponse.setParameter(1, length);
     uint64_t end = offset + length;
     if (end > edit->mSize) {
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/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 4be00c5..b963b13 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1668,14 +1668,6 @@
                 }
             }
 
-            // Back cancels action modes first.
-            if (mActionMode != null && keyCode == KeyEvent.KEYCODE_BACK) {
-                if (action == KeyEvent.ACTION_UP) {
-                    mActionMode.finish();
-                }
-                return true;
-            }
-
             if (!isDestroyed()) {
                 final Callback cb = getCallback();
                 final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
@@ -1684,6 +1676,7 @@
                     return true;
                 }
             }
+
             return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
                     : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
         }
@@ -1730,7 +1723,32 @@
         }
 
         public boolean superDispatchKeyEvent(KeyEvent event) {
-            return super.dispatchKeyEvent(event);
+            if (super.dispatchKeyEvent(event)) {
+                return true;
+            }
+
+            // Not handled by the view hierarchy, does the action bar want it
+            // to cancel out of something special?
+            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+                final int action = event.getAction();
+                // Back cancels action modes first.
+                if (mActionMode != null) {
+                    if (action == KeyEvent.ACTION_UP) {
+                        mActionMode.finish();
+                    }
+                    return true;
+                }
+
+                // Next collapse any expanded action views.
+                if (mActionBar != null && mActionBar.hasExpandedActionView()) {
+                    if (action == KeyEvent.ACTION_UP) {
+                        mActionBar.collapseActionView();
+                    }
+                    return true;
+                }
+            }
+
+            return false;
         }
 
         public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
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/MountService.java b/services/java/com/android/server/MountService.java
index 94465fd..7f61c635 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1339,7 +1339,11 @@
             String state = mVolumeStates.get(mountPoint);
             if (state == null) {
                 Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
-                throw new IllegalArgumentException();
+                if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
+                    state = Environment.MEDIA_REMOVED;
+                } else {
+                    throw new IllegalArgumentException();
+                }
             }
 
             return state;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index f99951fa..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();
         }
     }
 
@@ -935,9 +980,11 @@
             }
         }
 
-        public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+        public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId)
+                throws RemoteException {
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
                 if (!permissionGranted) {
                     return null;
@@ -975,15 +1022,16 @@
         }
 
         public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
-                String text) {
+                String text) throws RemoteException {
             return findAccessibilityNodeInfosByViewText(text,
                     mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID);
         }
 
         public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
-                int accessibilityWindowId, int accessibilityViewId) {
+                int accessibilityWindowId, int accessibilityViewId) throws RemoteException {
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
                 if (!permissionGranted) {
@@ -1026,9 +1074,10 @@
         }
 
         public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
-                int accessibilityWindowId, int accessibilityViewId) {
+                int accessibilityWindowId, int accessibilityViewId) throws RemoteException {
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted =
                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
                 if (!permissionGranted) {
@@ -1199,6 +1248,15 @@
             return service.mCanRetrieveScreenContent;
         }
 
+        public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
+            // This happens due to incorrect registration so make it apparent.
+            if (!canRetrieveWindowContent(service)) {
+                Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
+                        "declare android:canRetrieveWindowContent.");
+                throw new RemoteException();
+            }
+        }
+
         private boolean isRetrievalAllowingWindow(int windowId) {
             return (mRetrievalAlowingWindowId == windowId);
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f546cf1..94af46d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3610,8 +3610,10 @@
 
         String processName = app.processName;
         try {
-            thread.asBinder().linkToDeath(new AppDeathRecipient(
-                    app, pid, thread), 0);
+            AppDeathRecipient adr = new AppDeathRecipient(
+                    app, pid, thread);
+            thread.asBinder().linkToDeath(adr, 0);
+            app.deathRecipient = adr;
         } catch (RemoteException e) {
             app.resetPackageList();
             startProcessLocked(app, "link fail", processName);
@@ -3687,6 +3689,7 @@
             Slog.w(TAG, "Exception thrown during bind!", e);
 
             app.resetPackageList();
+            app.unlinkDeathRecipient();
             startProcessLocked(app, "bind fail", processName);
             return false;
         }
@@ -8885,25 +8888,59 @@
         pw.println("Applications Graphics Acceleration Info:");
         pw.println("Uptime: " + uptime + " Realtime: " + realtime);
         
-        String callArgs[] = {"graphics"};
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = procs.get(i);
             if (r.thread != null) {
                 pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **");
                 pw.flush();
                 try {
-                    TransferPipe.goDump(r.thread.asBinder(), fd, callArgs);
+                    TransferPipe tp = new TransferPipe();
+                    try {
+                        r.thread.dumpGfxInfo(tp.getWriteFd().getFileDescriptor(), args);
+                        tp.go(fd);
+                    } finally {
+                        tp.kill();
+                    }
                 } catch (IOException e) {
-                    pw.println("Failure: " + e);
+                    pw.println("Failure while dumping the app: " + r);
                     pw.flush();
                 } catch (RemoteException e) {
-                    pw.println("Got RemoteException!");
+                    pw.println("Got a RemoteException while dumping the app " + r);
                     pw.flush();
                 }
             }
         }
     }
 
+    final static class MemItem {
+        final String label;
+        final long pss;
+
+        public MemItem(String _label, long _pss) {
+            label = _label;
+            pss = _pss;
+        }
+    }
+
+    final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items) {
+        Collections.sort(items, new Comparator<MemItem>() {
+            @Override
+            public int compare(MemItem lhs, MemItem rhs) {
+                if (lhs.pss < rhs.pss) {
+                    return 1;
+                } else if (lhs.pss > rhs.pss) {
+                    return -1;
+                }
+                return 0;
+            }
+        });
+
+        for (int i=0; i<items.size(); i++) {
+            MemItem mi = items.get(i);
+            pw.print(prefix); pw.printf("%8d Kb: ", mi.pss); pw.println(mi.label);
+        }
+    }
+
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, String prefix, String[] args) {
         ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
@@ -8923,6 +8960,11 @@
             pw.println("Applications Memory Usage (kB):");
             pw.println("Uptime: " + uptime + " Realtime: " + realtime);
         }
+
+        ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+        long nativePss=0, dalvikPss=0, otherPss=0;
+        long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = procs.get(i);
             if (r.thread != null) {
@@ -8930,19 +8972,48 @@
                     pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
                     pw.flush();
                 }
+                Debug.MemoryInfo mi = null;
                 try {
-                    TransferPipe.goDump(r.thread.asBinder(), fd, args);
-                } catch (IOException e) {
-                    pw.println("Failure: " + e);
-                    pw.flush();
+                    mi = r.thread.dumpMemInfo(fd, args);
                 } catch (RemoteException e) {
                     if (!isCheckinRequest) {
                         pw.println("Got RemoteException!");
                         pw.flush();
                     }
                 }
+                if (!isCheckinRequest && mi != null) {
+                    procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")",
+                            mi.getTotalPss()));
+
+                    nativePss += mi.nativePss;
+                    dalvikPss += mi.dalvikPss;
+                    otherPss += mi.otherPss;
+                    for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+                        long mem = mi.getOtherPss(j);
+                        miscPss[j] += mem;
+                        otherPss -= mem;
+                    }
+                }
             }
         }
+
+        if (!isCheckinRequest && procs.size() > 1) {
+            ArrayList<MemItem> catMems = new ArrayList<MemItem>();
+
+            catMems.add(new MemItem("Native", nativePss));
+            catMems.add(new MemItem("Dalvik", dalvikPss));
+            catMems.add(new MemItem("Unknown", otherPss));
+            for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+                catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
+            }
+
+            pw.println();
+            pw.println("Total PSS by process:");
+            dumpMemItems(pw, "  ", procMems);
+            pw.println();
+            pw.println("Total PSS by category:");
+            dumpMemItems(pw, "  ", catMems);
+        }
     }
 
     /**
@@ -9142,6 +9213,7 @@
         app.notResponding = false;
         
         app.resetPackageList();
+        app.unlinkDeathRecipient();
         app.thread = null;
         app.forcingToForeground = null;
         app.foregroundServices = false;
@@ -9259,7 +9331,6 @@
             // This app is persistent, so we need to keep its record around.
             // If it is not already on the pending app list, add it there
             // and start a new process for it.
-            app.thread = null;
             app.forcingToForeground = null;
             app.foregroundServices = false;
             if (mPersistentStartingProcesses.indexOf(app) < 0) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 99830f9..9e597aa 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -73,6 +73,7 @@
     int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
     int lruSeq;                 // Sequence id for identifying LRU update cycles
     CompatibilityInfo compat;   // last used compatibility mode
+    IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
     ComponentName instrumentationClass;// class installed to instrument app
     ApplicationInfo instrumentationInfo; // the application being instrumented
     String instrumentationProfileFile; // where to save profiling
@@ -297,6 +298,13 @@
         }
     }
     
+    public void unlinkDeathRecipient() {
+        if (deathRecipient != null && thread != null) {
+            thread.asBinder().unlinkToDeath(deathRecipient, 0);
+        }
+        deathRecipient = null;
+    }
+
     public String toShortString() {
         if (shortStringName != null) {
             return shortStringName;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 0c78fe7..435c394 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED;
@@ -174,10 +175,12 @@
 
     /** Current policy for network templates. */
     private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
+    /** Current derived network rules for ifaces. */
+    private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
 
     /** Current policy for each UID. */
     private SparseIntArray mUidPolicy = new SparseIntArray();
-    /** Current derived network rules for each UID. */
+    /** Current derived rules for each UID. */
     private SparseIntArray mUidRules = new SparseIntArray();
 
     /** Set of ifaces that are metered. */
@@ -199,8 +202,6 @@
     // TODO: keep whitelist of system-critical services that should never have
     // rules enforced, such as system, phone, and radio UIDs.
 
-    // TODO: watch for package added broadcast to catch new UIDs.
-
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             IPowerManager powerManager, INetworkStatsService networkStats,
             INetworkManagementService networkManagement) {
@@ -242,7 +243,6 @@
         synchronized (mRulesLock) {
             // read policy from disk
             readPolicyLocked();
-            updateNotificationsLocked();
         }
 
         updateScreenOn();
@@ -268,9 +268,12 @@
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
 
-        // listen for uid removal to clean policy
-        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
-        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+        // listen for package/uid changes to update policy
+        final IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(ACTION_UID_REMOVED);
+        packageFilter.addDataScheme("package");
+        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
 
         // listen for stats update events
         final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
@@ -331,17 +334,28 @@
         }
     };
 
-    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and UID_REMOVED is protected
-            // broadcast.
+            // on background handler thread, and PACKAGE_ADDED and UID_REMOVED
+            // are protected broadcasts.
+
+            final String action = intent.getAction();
             final int uid = intent.getIntExtra(EXTRA_UID, 0);
             synchronized (mRulesLock) {
-                // remove any policy and update rules to clean up
-                mUidPolicy.delete(uid);
-                updateRulesForUidLocked(uid);
-                writePolicyLocked();
+                if (ACTION_PACKAGE_ADDED.equals(action)) {
+                    // update rules for UID, since it might be subject to
+                    // global background data policy.
+                    if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
+                    updateRulesForUidLocked(uid);
+
+                } else if (ACTION_UID_REMOVED.equals(action)) {
+                    // remove any policy and update rules to clean up.
+                    if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
+                    mUidPolicy.delete(uid);
+                    updateRulesForUidLocked(uid);
+                    writePolicyLocked();
+                }
             }
         }
     };
@@ -396,8 +410,8 @@
         // TODO: when switching to kernel notifications, compute next future
         // cycle boundary to recompute notifications.
 
-        // examine stats for each policy defined
-        for (NetworkPolicy policy : mNetworkPolicy) {
+        // examine stats for each active policy
+        for (NetworkPolicy policy : mNetworkRules.keySet()) {
             final long start = computeLastCycleBoundary(currentTime, policy);
             final long end = currentTime;
 
@@ -424,6 +438,15 @@
                     cancelNotification(policy, TYPE_WARNING);
                 }
             }
+
+        }
+
+        // clear notifications for non-active policies
+        for (NetworkPolicy policy : mNetworkPolicy) {
+            if (!mNetworkRules.containsKey(policy)) {
+                cancelNotification(policy, TYPE_WARNING);
+                cancelNotification(policy, TYPE_LIMIT);
+            }
         }
     }
 
@@ -531,7 +554,8 @@
             // permission above.
             synchronized (mRulesLock) {
                 ensureActiveMobilePolicyLocked();
-                updateIfacesLocked();
+                updateNetworkRulesLocked();
+                updateNotificationsLocked();
             }
         }
     };
@@ -541,7 +565,7 @@
      * {@link NetworkPolicy} that need to be enforced. When matches found, set
      * remaining quota based on usage cycle and historical stats.
      */
-    private void updateIfacesLocked() {
+    private void updateNetworkRulesLocked() {
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
         final NetworkState[] states;
@@ -565,7 +589,7 @@
         }
 
         // build list of rules and ifaces to enforce them against
-        final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
+        mNetworkRules.clear();
         final ArrayList<String> ifaceList = Lists.newArrayList();
         for (NetworkPolicy policy : mNetworkPolicy) {
 
@@ -580,7 +604,7 @@
 
             if (ifaceList.size() > 0) {
                 final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
-                rules.put(policy, ifaces);
+                mNetworkRules.put(policy, ifaces);
             }
         }
 
@@ -596,8 +620,8 @@
 
         // apply each policy that we found ifaces for; compute remaining data
         // based on current cycle and historical stats, and push to kernel.
-        for (NetworkPolicy policy : rules.keySet()) {
-            final String[] ifaces = rules.get(policy);
+        for (NetworkPolicy policy : mNetworkRules.keySet()) {
+            final String[] ifaces = mNetworkRules.get(policy);
 
             final long start = computeLastCycleBoundary(currentTime, policy);
             final long end = currentTime;
@@ -670,17 +694,17 @@
         if (!mobileDefined) {
             Slog.i(TAG, "no policy for active mobile network; generating default policy");
 
-            // default mobile policy has combined 4GB warning, and assume usage
-            // cycle starts today today.
+            // build default mobile policy, and assume usage cycle starts today
+            final long warningBytes = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_networkPolicyDefaultWarning)
+                    * MB_IN_BYTES;
 
-            // TODO: move this policy definition to overlay or secure setting
             final Time time = new Time(Time.TIMEZONE_UTC);
             time.setToNow();
             final int cycleDay = time.monthDay;
 
             final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
-            mNetworkPolicy.add(
-                    new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
+            mNetworkPolicy.add(new NetworkPolicy(template, cycleDay, warningBytes, LIMIT_DISABLED));
             writePolicyLocked();
         }
     }
@@ -859,7 +883,7 @@
                 mNetworkPolicy.add(policy);
             }
 
-            updateIfacesLocked();
+            updateNetworkRulesLocked();
             updateNotificationsLocked();
             writePolicyLocked();
         }
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 7ec6b81..6cc01f4 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -60,6 +60,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.INetworkManagementService;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -112,6 +113,8 @@
     private final TrustedTime mTime;
     private final NetworkStatsSettings mSettings;
 
+    private final PowerManager.WakeLock mWakeLock;
+
     private IConnectivityManager mConnManager;
 
     // @VisibleForTesting
@@ -191,6 +194,10 @@
         mTime = checkNotNull(time, "missing TrustedTime");
         mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
 
+        final PowerManager powerManager = (PowerManager) context.getSystemService(
+                Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
@@ -408,7 +415,12 @@
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
             // permission above.
             synchronized (mStatsLock) {
-                updateIfacesLocked();
+                mWakeLock.acquire();
+                try {
+                    updateIfacesLocked();
+                } finally {
+                    mWakeLock.release();
+                }
             }
         }
     };
@@ -419,8 +431,12 @@
             // on background handler thread, and verified UPDATE_DEVICE_STATS
             // permission above.
             synchronized (mStatsLock) {
-                // TODO: acquire wakelock while performing poll
-                performPollLocked(true, false);
+                mWakeLock.acquire();
+                try {
+                    performPollLocked(true, false);
+                } finally {
+                    mWakeLock.release();
+                }
             }
         }
     };
@@ -433,7 +449,12 @@
             final int uid = intent.getIntExtra(EXTRA_UID, 0);
             synchronized (mStatsLock) {
                 // TODO: perform one last stats poll for UID
-                removeUidLocked(uid);
+                mWakeLock.acquire();
+                try {
+                    removeUidLocked(uid);
+                } finally {
+                    mWakeLock.release();
+                }
             }
         }
     };
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/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66120a1..f7e0c66 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -61,7 +61,7 @@
     /** @hide */
     public TelephonyManager(Context context) {
         if (sContext == null) {
-            sContext = context;
+            sContext = context.getApplicationContext();
 
             sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                     "telephony.registry"));
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
+    }
+}