Merge changes I799532f7,I5cffa6eb

* changes:
  SurfaceTexture: fix a comment
  SurfaceTexture: remove getAllocator
diff --git a/Android.mk b/Android.mk
index 335fb73..3b0fc59 100644
--- a/Android.mk
+++ b/Android.mk
@@ -158,6 +158,11 @@
 	core/java/com/android/internal/os/IResultReceiver.aidl \
 	core/java/com/android/internal/statusbar/IStatusBar.aidl \
 	core/java/com/android/internal/statusbar/IStatusBarService.aidl \
+	core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
+	core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
+	core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
+	core/java/com/android/internal/textservice/ITextServicesManager.aidl \
+	core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
 	core/java/com/android/internal/view/IInputMethod.aidl \
@@ -266,6 +271,11 @@
 	frameworks/base/core/java/android/view/Surface.aidl \
 	frameworks/base/core/java/android/view/WindowManager.aidl \
 	frameworks/base/core/java/android/widget/RemoteViews.aidl \
+	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerService.aidl \
+	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \
+	frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
+	frameworks/base/core/java/com/android/internal/textservice/ITextServicesManager.aidl \
+	frameworks/base/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputContext.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputMethod.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputMethodCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 0976380..f88001d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,6 +21,7 @@
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+    field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
@@ -4783,6 +4784,7 @@
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
+    field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String UI_MODE_SERVICE = "uimode";
     field public static final java.lang.String USB_SERVICE = "usb";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
@@ -17941,6 +17943,30 @@
 
 }
 
+package android.service.textservice {
+
+  public abstract class SpellCheckerService extends android.app.Service {
+    ctor public SpellCheckerService();
+    method public void cancel();
+    method public abstract android.view.textservice.SuggestionsInfo getSuggestions(android.view.textservice.TextInfo, int, java.lang.String);
+    method public android.view.textservice.SuggestionsInfo[] getSuggestionsMultiple(android.view.textservice.TextInfo[], java.lang.String, int, boolean);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    field public static final java.lang.String SERVICE_INTERFACE;
+  }
+
+  public class SpellCheckerSession {
+    method public void close();
+    method public void getSuggestions(android.view.textservice.TextInfo, int);
+    method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
+    method public boolean isSessionDisconnected();
+  }
+
+  public static abstract interface SpellCheckerSession.SpellCheckerSessionListener {
+    method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
+  }
+
+}
+
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -21004,6 +21030,11 @@
     method public void onPrepareSubMenu(android.view.SubMenu);
   }
 
+  public abstract interface CollapsibleActionView {
+    method public abstract void onActionViewCollapsed();
+    method public abstract void onActionViewExpanded();
+  }
+
   public abstract interface ContextMenu implements android.view.Menu {
     method public abstract void clearHeader();
     method public abstract android.view.ContextMenu setHeaderIcon(int);
@@ -22714,10 +22745,8 @@
     ctor public ViewDebug();
     method public static void dumpCapturedView(java.lang.String, java.lang.Object);
     method public static void startHierarchyTracing(java.lang.String, android.view.View);
-    method public static void startLooperProfiling(java.io.File);
     method public static void startRecyclerTracing(java.lang.String, android.view.View);
     method public static void stopHierarchyTracing();
-    method public static void stopLooperProfiling();
     method public static void stopRecyclerTracing();
     method public static void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
     method public static void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
@@ -24018,6 +24047,54 @@
 
 }
 
+package android.view.textservice {
+
+  public final class SpellCheckerInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getComponent();
+    method public java.lang.String getId();
+    method public java.lang.String getPackageName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class SuggestionsInfo implements android.os.Parcelable {
+    ctor public SuggestionsInfo(int, java.lang.String[]);
+    ctor public SuggestionsInfo(int, java.lang.String[], int, int);
+    ctor public SuggestionsInfo(android.os.Parcel);
+    method public int describeContents();
+    method public int getCookie();
+    method public int getSequence();
+    method public java.lang.String getSuggestionAt(int);
+    method public int getSuggestionsAttributes();
+    method public int getSuggestionsCount();
+    method public void setCookieAndSequence(int, int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
+    field public static final int RESULT_ATTR_LOOKS_TYPO = 4; // 0x4
+    field public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 2; // 0x2
+  }
+
+  public final class TextInfo implements android.os.Parcelable {
+    ctor public TextInfo(java.lang.String);
+    ctor public TextInfo(java.lang.String, int, int);
+    ctor public TextInfo(android.os.Parcel);
+    method public int describeContents();
+    method public int getCookie();
+    method public int getSequence();
+    method public java.lang.String getText();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class TextServicesManager {
+    method public android.view.textservice.SpellCheckerInfo getCurrentSpellChecker(java.util.Locale);
+    method public android.service.textservice.SpellCheckerSession newSpellCheckerSession(android.view.textservice.SpellCheckerInfo, java.util.Locale, android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener);
+  }
+
+}
+
 package android.webkit {
 
   public final deprecated class CacheManager {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3fb1736..6dfa12b 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -468,10 +468,16 @@
         String profileFile = null;
         boolean start = false;
         boolean wall = false;
+        int profileType = 0;
         
         String process = null;
         
         String cmd = nextArgRequired();
+        if ("looper".equals(cmd)) {
+            cmd = nextArgRequired();
+            profileType = 1;
+        }
+
         if ("start".equals(cmd)) {
             start = true;
             wall = "--wall".equals(nextOption());
@@ -516,7 +522,7 @@
             } else if (start) {
                 //removeWallOption();
             }
-            if (!mAm.profileControl(process, start, profileFile, fd)) {
+            if (!mAm.profileControl(process, start, profileFile, fd, profileType)) {
                 wall = false;
                 throw new AndroidException("PROFILE FAILED on process " + process);
             }
@@ -1076,8 +1082,8 @@
                 "       am broadcast <INTENT>\n" +
                 "       am instrument [-r] [-e <NAME> <VALUE>] [-p] [-w]\n" +
                 "               [--no-window-animation] <COMPONENT>\n" +
-                "       am profile start <PROCESS> <FILE>\n" +
-                "       am profile stop <PROCESS>\n" +
+                "       am profile [looper] start <PROCESS> <FILE>\n" +
+                "       am profile [looper] stop <PROCESS>\n" +
                 "       am dumpheap [flags] <PROCESS> <FILE>\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 2a731a3..b7cd829 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1104,10 +1104,11 @@
             data.enforceInterface(IActivityManager.descriptor);
             String process = data.readString();
             boolean start = data.readInt() != 0;
+            int profileType = data.readInt();
             String path = data.readString();
             ParcelFileDescriptor fd = data.readInt() != 0
                     ? data.readFileDescriptor() : null;
-            boolean res = profileControl(process, start, path, fd);
+            boolean res = profileControl(process, start, path, fd, profileType);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -2888,13 +2889,14 @@
     }
     
     public boolean profileControl(String process, boolean start,
-            String path, ParcelFileDescriptor fd) throws RemoteException
+            String path, ParcelFileDescriptor fd, int profileType) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(process);
         data.writeInt(start ? 1 : 0);
+        data.writeInt(profileType);
         data.writeString(path);
         if (fd != null) {
             data.writeInt(1);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f6cd866..9bbbd6c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -676,11 +676,12 @@
             queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
         }
 
-        public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
+        public void profilerControl(boolean start, String path, ParcelFileDescriptor fd,
+                int profileType) {
             ProfilerControlData pcd = new ProfilerControlData();
             pcd.path = path;
             pcd.fd = fd;
-            queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
+            queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0, profileType);
         }
 
         public void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) {
@@ -954,7 +955,7 @@
         }
 
         public void scheduleTrimMemory(int level) {
-            queueOrSendMessage(H.TRIM_MEMORY, level);
+            queueOrSendMessage(H.TRIM_MEMORY, null, level);
         }
     }
 
@@ -1148,7 +1149,7 @@
                     handleActivityConfigurationChanged((IBinder)msg.obj);
                     break;
                 case PROFILER_CONTROL:
-                    handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj);
+                    handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj, msg.arg2);
                     break;
                 case CREATE_BACKUP_AGENT:
                     handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
@@ -1184,8 +1185,10 @@
                     break;
                 case UPDATE_PACKAGE_COMPATIBILITY_INFO:
                     handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
+                    break;
                 case TRIM_MEMORY:
                     handleTrimMemory(msg.arg1);
+                    break;
             }
             if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
         }
@@ -3469,11 +3472,18 @@
         performConfigurationChanged(r.activity, mCompatConfiguration);
     }
 
-    final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
+    final void handleProfilerControl(boolean start, ProfilerControlData pcd, int profileType) {
         if (start) {
             try {
-                Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
-                        8 * 1024 * 1024, 0);
+                switch (profileType) {
+                    case 1:
+                        ViewDebug.startLooperProfiling(pcd.path, pcd.fd.getFileDescriptor());
+                        break;
+                    default:
+                        Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
+                                8 * 1024 * 1024, 0);
+                        break;
+                }
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Profiling failed on path " + pcd.path
                         + " -- can the process access this path?");
@@ -3485,7 +3495,15 @@
                 }
             }
         } else {
-            Debug.stopMethodTracing();
+            switch (profileType) {
+                case 1:
+                    ViewDebug.stopLooperProfiling();
+                    break;
+                default:
+                    Debug.stopMethodTracing();
+                    break;
+                    
+            }
         }
     }
 
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 942f245..9a5b527 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -376,10 +376,11 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             boolean start = data.readInt() != 0;
+            int profileType = data.readInt();
             String path = data.readString();
             ParcelFileDescriptor fd = data.readInt() != 0
                     ? data.readFileDescriptor() : null;
-            profilerControl(start, path, fd);
+            profilerControl(start, path, fd, profileType);
             return true;
         }
         
@@ -936,10 +937,11 @@
     }
     
     public void profilerControl(boolean start, String path,
-            ParcelFileDescriptor fd) throws RemoteException {
+            ParcelFileDescriptor fd, int profileType) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeInt(start ? 1 : 0);
+        data.writeInt(profileType);
         data.writeString(path);
         if (fd != null) {
             data.writeInt(1);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d2323e7..6289730 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -83,6 +83,7 @@
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textservice.TextServicesManager;
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.app.admin.DevicePolicyManager;
@@ -320,6 +321,11 @@
                     return InputMethodManager.getInstance(ctx);
                 }});
 
+        registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    return TextServicesManager.getInstance();
+                }});
+
         registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
                 public Object getService(ContextImpl ctx) {
                     // TODO: why isn't this caching it?  It wasn't
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index c82c9ec..789d3a6 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1695,6 +1695,7 @@
     
     public void dispatchDestroy() {
         mDestroyed = true;
+        execPendingActions();
         moveToState(Fragment.INITIALIZING, false);
         mActivity = null;
     }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 93c821c..64d77e8 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -284,7 +284,7 @@
     
     // Turn on/off profiling in a particular process.
     public boolean profileControl(String process, boolean start,
-            String path, ParcelFileDescriptor fd) throws RemoteException;
+            String path, ParcelFileDescriptor fd, int profileType) throws RemoteException;
     
     public boolean shutdown(int timeout) throws RemoteException;
     
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 9de0bf4..d0607d0 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -105,7 +105,7 @@
             throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
     void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
-    void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
+    void profilerControl(boolean start, String path, ParcelFileDescriptor fd, int profileType)
             throws RemoteException;
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
             throws RemoteException;
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 019652c..1ef99a1 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -388,6 +388,10 @@
                         TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
                 info.minHeight =
                         TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
+                info.minResizeWidth =
+                    TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
+                info.minResizeHeight =
+                    TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
             }
             return providers;
         }
@@ -411,6 +415,10 @@
                         TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
                 info.minHeight =
                         TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
+                info.minResizeWidth =
+                    TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
+                info.minResizeHeight =
+                    TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
             }
             return info;
         }
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index b8c5b02..9c352d5 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -187,6 +187,8 @@
         }
         this.minWidth = in.readInt();
         this.minHeight = in.readInt();
+        this.minResizeWidth = in.readInt();
+        this.minResizeHeight = in.readInt();
         this.updatePeriodMillis = in.readInt();
         this.initialLayout = in.readInt();
         if (0 != in.readInt()) {
@@ -208,6 +210,8 @@
         }
         out.writeInt(this.minWidth);
         out.writeInt(this.minHeight);
+        out.writeInt(this.minResizeWidth);
+        out.writeInt(this.minResizeHeight);
         out.writeInt(this.updatePeriodMillis);
         out.writeInt(this.initialLayout);
         if (this.configure != null) {
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index 92b98fd..37cc141 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -56,11 +56,8 @@
     static final int TRIM_MEMORY_COMPLETE = 80;
 
     /** @hide */
-    static final int TRIM_MEMORY_MODERATE = 60;
+    static final int TRIM_MEMORY_MODERATE = 50;
 
     /** @hide */
-    static final int TRIM_MEMORY_BACKGROUND = 40;
-
-    /** @hide */
-    static final int TRIM_MEMORY_INVISIBLE = 20;
+    static final int TRIM_MEMORY_BACKGROUND = 20;
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fed6d81..0a2253c8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1612,6 +1612,15 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.view.textservice.TextServicesManager} for accessing
+     * text services.
+     *
+     * @see #getSystemService
+     */
+    public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
      *
      * @hide
diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java
index eafff49..5cfa998 100644
--- a/core/java/android/inputmethodservice/ExtractEditLayout.java
+++ b/core/java/android/inputmethodservice/ExtractEditLayout.java
@@ -172,7 +172,10 @@
 
         @Override
         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
-            return mCallback.onActionItemClicked(this, item);
+            if (mCallback != null) {
+                return mCallback.onActionItemClicked(this, item);
+            }
+            return false;
         }
 
         @Override
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index a866436..b035c51 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -103,6 +103,10 @@
         public void interfaceRemoved(String iface) {
             mTracker.interfaceRemoved(iface);
         }
+
+        public void limitReached(String limitName, String iface) {
+            // Ignored.
+        }
     }
 
     private EthernetDataTracker() {
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index 4436e6e..a97f203 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -52,4 +52,14 @@
      * @param iface The interface.
      */
     void interfaceRemoved(String iface);
+
+    /**
+     * A networking quota limit has been reached. The quota might not
+     * be specific to an interface.
+     *
+     * @param limitName The name of the limit that triggered.
+     * @param iface The interface on which the limit was detected.
+     */
+    void limitReached(String limitName, String iface);
+
 }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 9826bec..132f3ba 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -58,8 +58,8 @@
     private ProxyProperties mHttpProxy;
 
     public static class CompareResult<T> {
-        public ArrayList<T> removed = new ArrayList<T>();
-        public ArrayList<T> added = new ArrayList<T>();
+        public Collection<T> removed = new ArrayList<T>();
+        public Collection<T> added = new ArrayList<T>();
 
         @Override
         public String toString() {
diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java
new file mode 100644
index 0000000..4582523
--- /dev/null
+++ b/core/java/android/net/VpnBuilder.java
@@ -0,0 +1,413 @@
+/*
+ * 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 android.net;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.net.VpnConfig;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.DatagramSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+
+/**
+ * VpnBuilder is a framework which enables applications to build their
+ * own VPN solutions. In general, it creates a virtual network interface,
+ * configures addresses and routing rules, and returns a file descriptor
+ * to the application. Each read from the descriptor retrieves an outgoing
+ * packet which was routed to the interface. Each write to the descriptor
+ * injects an incoming packet just like it was received from the interface.
+ * The framework is running on Internet Protocol (IP), so packets are
+ * always started with IP headers. The application then completes a VPN
+ * connection by processing and exchanging packets with a remote server
+ * over a secured tunnel.
+ *
+ * <p>Letting applications intercept packets raises huge security concerns.
+ * Besides, a VPN application can easily break the network, and two of them
+ * may conflict with each other. The framework takes several actions to
+ * address these issues. Here are some key points:
+ * <ul>
+ *   <li>User action is required to create a VPN connection.</li>
+ *   <li>There can be only one VPN connection running at the same time. The
+ *       existing interface is deactivated when a new one is created.</li>
+ *   <li>A system-managed notification is shown during the lifetime of a
+ *       VPN connection.</li>
+ *   <li>A system-managed dialog gives the information of the current VPN
+ *       connection. It also provides a button to disconnect.</li>
+ *   <li>The network is restored automatically when the file descriptor is
+ *       closed. It also covers the cases when a VPN application is crashed
+ *       or killed by the system.</li>
+ * </ul>
+ *
+ * <p>There are two primary methods in this class: {@link #prepare} and
+ * {@link #establish}. The former deals with the user action and stops
+ * the existing VPN connection created by another application. The latter
+ * creates a VPN interface using the parameters supplied to this builder.
+ * An application must call {@link #prepare} to grant the right to create
+ * an interface, and it can be revoked at any time by another application.
+ * The application got revoked is notified by an {@link #ACTION_VPN_REVOKED}
+ * broadcast. Here are the general steps to create a VPN connection:
+ * <ol>
+ *   <li>When the user press the button to connect, call {@link #prepare}
+ *       and launch the intent if necessary.</li>
+ *   <li>Register a receiver for {@link #ACTION_VPN_REVOKED} broadcasts.
+ *   <li>Connect to the remote server and negotiate the network parameters
+ *       of the VPN connection.</li>
+ *   <li>Use those parameters to configure a VpnBuilder and create a VPN
+ *       interface by calling {@link #establish}.</li>
+ *   <li>Start processing packets between the returned file descriptor and
+ *       the VPN tunnel.</li>
+ *   <li>When an {@link #ACTION_VPN_REVOKED} broadcast is received, the
+ *       interface is already deactivated by the framework. Close the file
+ *       descriptor and shut down the VPN tunnel gracefully.
+ * </ol>
+ * Methods in this class can be used in activities and services. However,
+ * the intent returned from {@link #prepare} must be launched from an
+ * activity. The broadcast receiver can be registered at any time, but doing
+ * it before calling {@link #establish} effectively avoids race conditions.
+ *
+ * <p class="note">Using this class requires
+ * {@link android.Manifest.permission#VPN} permission.
+ * @hide
+ */
+public class VpnBuilder {
+
+    /**
+     * Broadcast intent action indicating that the VPN application has been
+     * revoked. This can be only received by the target application on the
+     * receiver explicitly registered using {@link Context#registerReceiver}.
+     *
+     * <p>This is a protected intent that can only be sent by the system.
+     */
+    public static final String ACTION_VPN_REVOKED = VpnConfig.ACTION_VPN_REVOKED;
+
+    /**
+     * Use IConnectivityManager instead since those methods are hidden and
+     * not available in ConnectivityManager.
+     */
+    private static IConnectivityManager getService() {
+        return IConnectivityManager.Stub.asInterface(
+                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+    }
+
+    /**
+     * Prepare to establish a VPN connection. This method returns {@code null}
+     * if the VPN application is already prepared. Otherwise, it returns an
+     * {@link Intent} to a system activity. The application should launch the
+     * activity using {@link Activity#startActivityForResult} to get itself
+     * prepared. The activity may pop up a dialog to require user action, and
+     * the result will come back to the application through its
+     * {@link Activity#onActivityResult}. The application becomes prepared if
+     * the result is {@link Activity#RESULT_OK}, and it is granted to create a
+     * VPN interface by calling {@link #establish}.
+     *
+     * <p>Only one application can be granted at the same time. The right
+     * is revoked when another application is granted. The application
+     * losing the right will be notified by an {@link #ACTION_VPN_REVOKED}
+     * broadcast, and its VPN interface will be deactivated by the system.
+     * The application should then notify the remote server and disconnect
+     * gracefully. Unless the application becomes prepared again, subsequent
+     * calls to {@link #establish} will return {@code null}.
+     *
+     * @see #establish
+     * @see #ACTION_VPN_REVOKED
+     */
+    public static Intent prepare(Context context) {
+        try {
+            if (getService().prepareVpn(context.getPackageName(), null)) {
+                return null;
+            }
+        } catch (RemoteException e) {
+            // ignore
+        }
+        return VpnConfig.getIntentForConfirmation();
+    }
+
+    private VpnConfig mConfig = new VpnConfig();
+    private StringBuilder mAddresses = new StringBuilder();
+    private StringBuilder mRoutes = new StringBuilder();
+
+    /**
+     * Set the name of this session. It will be displayed in system-managed
+     * dialogs and notifications. This is recommended not required.
+     */
+    public VpnBuilder setSession(String session) {
+        mConfig.session = session;
+        return this;
+    }
+
+    /**
+     * Set the {@link PendingIntent} to an activity for users to configure
+     * the VPN connection. If it is not set, the button to configure will
+     * not be shown in system-managed dialogs.
+     */
+    public VpnBuilder setConfigureIntent(PendingIntent intent) {
+        mConfig.configureIntent = intent;
+        return this;
+    }
+
+    /**
+     * Set the maximum transmission unit (MTU) of the VPN interface. If it
+     * is not set, the default value in the operating system will be used.
+     *
+     * @throws IllegalArgumentException if the value is not positive.
+     */
+    public VpnBuilder setMtu(int mtu) {
+        if (mtu <= 0) {
+            throw new IllegalArgumentException("Bad mtu");
+        }
+        mConfig.mtu = mtu;
+        return this;
+    }
+
+    /**
+     * Private method to validate address and prefixLength.
+     */
+    private static void check(InetAddress address, int prefixLength) {
+        if (address.isLoopbackAddress()) {
+            throw new IllegalArgumentException("Bad address");
+        }
+        if (address instanceof Inet4Address) {
+            if (prefixLength < 0 || prefixLength > 32) {
+                throw new IllegalArgumentException("Bad prefixLength");
+            }
+        } else if (address instanceof Inet6Address) {
+            if (prefixLength < 0 || prefixLength > 128) {
+                throw new IllegalArgumentException("Bad prefixLength");
+            }
+        } else {
+            throw new IllegalArgumentException("Unsupported family");
+        }
+    }
+
+    /**
+     * Convenience method to add a network address to the VPN interface
+     * using a numeric address string. See {@link InetAddress} for the
+     * definitions of numeric address formats.
+     *
+     * @throws IllegalArgumentException if the address is invalid.
+     * @see #addAddress(InetAddress, int)
+     */
+    public VpnBuilder addAddress(String address, int prefixLength) {
+        return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
+    }
+
+    /**
+     * Add a network address to the VPN interface. Both IPv4 and IPv6
+     * addresses are supported. At least one address must be set before
+     * calling {@link #establish}.
+     *
+     * @throws IllegalArgumentException if the address is invalid.
+     */
+    public VpnBuilder addAddress(InetAddress address, int prefixLength) {
+        check(address, prefixLength);
+
+        if (address.isAnyLocalAddress()) {
+            throw new IllegalArgumentException("Bad address");
+        }
+
+        mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
+        return this;
+    }
+
+    /**
+     * Convenience method to add a network route to the VPN interface
+     * using a numeric address string. See {@link InetAddress} for the
+     * definitions of numeric address formats.
+     *
+     * @see #addRoute(InetAddress, int)
+     * @throws IllegalArgumentException if the route is invalid.
+     */
+    public VpnBuilder addRoute(String address, int prefixLength) {
+        return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
+    }
+
+    /**
+     * Add a network route to the VPN interface. Both IPv4 and IPv6
+     * routes are supported.
+     *
+     * @throws IllegalArgumentException if the route is invalid.
+     */
+    public VpnBuilder addRoute(InetAddress address, int prefixLength) {
+        check(address, prefixLength);
+
+        int offset = prefixLength / 8;
+        byte[] bytes = address.getAddress();
+        if (offset < bytes.length) {
+            if ((byte)(bytes[offset] << (prefixLength % 8)) != 0) {
+                throw new IllegalArgumentException("Bad address");
+            }
+            while (++offset < bytes.length) {
+                if (bytes[offset] != 0) {
+                    throw new IllegalArgumentException("Bad address");
+                }
+            }
+        }
+
+        mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
+        return this;
+    }
+
+    /**
+     * Convenience method to add a DNS server to the VPN connection
+     * using a numeric address string. See {@link InetAddress} for the
+     * definitions of numeric address formats.
+     *
+     * @throws IllegalArgumentException if the address is invalid.
+     * @see #addDnsServer(InetAddress)
+     */
+    public VpnBuilder addDnsServer(String address) {
+        return addDnsServer(InetAddress.parseNumericAddress(address));
+    }
+
+    /**
+     * Add a DNS server to the VPN connection. Both IPv4 and IPv6
+     * addresses are supported. If none is set, the DNS servers of
+     * the default network will be used.
+     *
+     * @throws IllegalArgumentException if the address is invalid.
+     */
+    public VpnBuilder addDnsServer(InetAddress address) {
+        if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
+            throw new IllegalArgumentException("Bad address");
+        }
+        if (mConfig.dnsServers == null) {
+            mConfig.dnsServers = new ArrayList<String>();
+        }
+        mConfig.dnsServers.add(address.getHostAddress());
+        return this;
+    }
+
+    /**
+     * Add a search domain to the DNS resolver.
+     */
+    public VpnBuilder addSearchDomain(String domain) {
+        if (mConfig.searchDomains == null) {
+            mConfig.searchDomains = new ArrayList<String>();
+        }
+        mConfig.searchDomains.add(domain);
+        return this;
+    }
+
+    /**
+     * Create a VPN interface using the parameters supplied to this builder.
+     * The interface works on IP packets, and a file descriptor is returned
+     * for the application to access them. Each read retrieves an outgoing
+     * packet which was routed to the interface. Each write injects an
+     * incoming packet just like it was received from the interface. The file
+     * descriptor is put into non-blocking mode by default to avoid blocking
+     * Java threads. To use the file descriptor completely in native space,
+     * see {@link ParcelFileDescriptor#detachFd()}. The application MUST
+     * close the file descriptor when the VPN connection is terminated. The
+     * VPN interface will be removed and the network will be restored by the
+     * framework automatically.
+     *
+     * <p>To avoid conflicts, there can be only one active VPN interface at
+     * the same time. Usually network parameters are never changed during the
+     * lifetime of a VPN connection. It is also common for an application to
+     * create a new file descriptor after closing the previous one. However,
+     * it is rare but not impossible to have two interfaces while performing a
+     * seamless handover. In this case, the old interface will be deactivated
+     * when the new one is configured successfully. Both file descriptors are
+     * valid but now outgoing packets will be routed to the new interface.
+     * Therefore, after draining the old file descriptor, the application MUST
+     * close it and start using the new file descriptor. If the new interface
+     * cannot be created, the existing interface and its file descriptor remain
+     * untouched.
+     *
+     * <p>An exception will be thrown if the interface cannot be created for
+     * any reason. However, this method returns {@code null} if the application
+     * is not prepared or is revoked by another application. This helps solve
+     * possible race conditions while handling {@link #ACTION_VPN_REVOKED}
+     * broadcasts.
+     *
+     * @return {@link ParcelFileDescriptor} of the VPN interface, or
+     *         {@code null} if the application is not prepared.
+     * @throws IllegalArgumentException if a parameter is not accepted by the
+     *         operating system.
+     * @throws IllegalStateException if a parameter cannot be applied by the
+     *         operating system.
+     * @see #prepare
+     */
+    public ParcelFileDescriptor establish() {
+        mConfig.addresses = mAddresses.toString();
+        mConfig.routes = mRoutes.toString();
+
+        try {
+            return getService().establishVpn(mConfig);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Protect a socket from VPN connections. The socket will be bound to the
+     * current default network interface, so its traffic will not be forwarded
+     * through VPN. This method is useful if some connections need to be kept
+     * outside of VPN. For example, a VPN tunnel should protect itself if its
+     * destination is covered by VPN routes. Otherwise its outgoing packets
+     * will be sent back to the VPN interface and cause an infinite loop.
+     *
+     * <p>The socket is NOT closed by this method.
+     *
+     * @return {@code true} on success.
+     */
+    public static boolean protect(int socket) {
+        ParcelFileDescriptor dup = null;
+        try {
+            dup = ParcelFileDescriptor.fromFd(socket);
+            return getService().protectVpn(dup);
+        } catch (Exception e) {
+            return false;
+        } finally {
+            try {
+                dup.close();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Protect a {@link Socket} from VPN connections.
+     *
+     * @return {@code true} on success.
+     * @see #protect(int)
+     */
+    public static boolean protect(Socket socket) {
+        return protect(socket.getFileDescriptor$().getInt$());
+    }
+
+    /**
+     * Protect a {@link DatagramSocket} from VPN connections.
+     *
+     * @return {@code true} on success.
+     * @see #protect(int)
+     */
+    public static boolean protect(DatagramSocket socket) {
+        return protect(socket.getFileDescriptor$().getInt$());
+    }
+}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index cd39d5c..bc37244 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -361,7 +361,8 @@
 
     /**
      * Remove any pending posts of Runnable <var>r</var> with Object
-     * <var>token</var> that are in the message queue.
+     * <var>token</var> that are in the message queue.  If <var>token</var> is null,
+     * all callbacks will be removed.
      */
     public final void removeCallbacks(Runnable r, Object token)
     {
@@ -517,7 +518,8 @@
 
     /**
      * Remove any pending posts of messages with code 'what' and whose obj is
-     * 'object' that are in the message queue.
+     * 'object' that are in the message queue.  If <var>token</var> is null,
+     * all messages will be removed.
      */
     public final void removeMessages(int what, Object object) {
         mQueue.removeMessages(this, what, object, true);
@@ -525,7 +527,8 @@
 
     /**
      * Remove any pending posts of callbacks and sent messages whose
-     * <var>obj</var> is <var>token</var>.
+     * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
+     * all callbacks and messages will be removed.
      */
     public final void removeCallbacksAndMessages(Object token) {
         mQueue.removeCallbacksAndMessages(this, token);
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index c90de17..78c9010 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -563,6 +563,12 @@
             // Single pane, showing just a prefs fragment.
             findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
             mPrefsContainer.setVisibility(View.VISIBLE);
+            if (initialTitle != 0) {
+                CharSequence initialTitleStr = getText(initialTitle);
+                CharSequence initialShortTitleStr = initialShortTitle != 0
+                        ? getText(initialShortTitle) : null;
+                showBreadCrumbs(initialTitleStr, initialShortTitleStr);
+            }
         } else if (mHeaders.size() > 0) {
             setListAdapter(new HeaderAdapter(this, mHeaders));
             if (!mSinglePane) {
@@ -1093,6 +1099,10 @@
         } else {
             getListView().clearChoices();
         }
+        showBreadCrumbs(header);
+    }
+
+    void showBreadCrumbs(Header header) {
         if (header != null) {
             CharSequence title = header.getBreadCrumbTitle(getResources());
             if (title == null) title = header.getTitle(getResources());
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c299891..4a719ec 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1439,6 +1439,13 @@
                 CONTENT_URI, "strequent");
 
         /**
+         * The content:// style URI for showing frequently contacted person listing.
+         * @hide
+         */
+        public static final Uri CONTENT_FREQUENT_URI = Uri.withAppendedPath(
+                CONTENT_URI, "frequent");
+
+        /**
          * The content:// style URI used for "type-to-filter" functionality on the
          * {@link #CONTENT_STREQUENT_URI} URI. The filter string will be used to match
          * various parts of the contact name. The filter argument should be passed
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cb87e94..1cd46de 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,8 +16,6 @@
 
 package android.provider;
 
-
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.SearchManager;
@@ -48,7 +46,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 
-
 /**
  * The Settings provider contains global system-level device preferences.
  */
@@ -3737,6 +3734,15 @@
          */
         public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
 
+
+        /**
+         * The {@link ComponentName} string of the service to be used as the spell checker
+         * service which is one of the services managed by the text service manager.
+         *
+         * @hide
+         */
+        public static final String SPELL_CHECKER_SERVICE = "spell_checker_service";
+
         /**
          * What happens when the user presses the Power button while in-call
          * and the screen is on.<br/>
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index ab569a1..d68d8ba 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -527,10 +527,19 @@
                 break;
             case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
                 address = (String)msg.obj;
-                if (address != null) {
+                if (address == null) return;
+                int attempt = mBondState.getAttempt(address);
+
+                // Try only if attemps are in progress and cap it 2 attempts
+                // The 2 attempts cap is a fail safe if the stack returns
+                // an incorrect error code for bonding failures and if the pin
+                // is entered wrongly twice we should abort.
+                if (attempt > 0 && attempt <= 2) {
+                    mBondState.attempt(address);
                     createBond(address);
                     return;
                 }
+                if (attempt > 0) mBondState.clearPinAttempts(address);
                 break;
             }
         }
@@ -741,7 +750,6 @@
                     BluetoothDevice.BOND_NONE, result);
             return;
         }
-        mBondState.attempt(address);
     }
 
     /*package*/ BluetoothDevice getRemoteDevice(String address) {
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
new file mode 100644
index 0000000..6ac99ca
--- /dev/null
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -0,0 +1,140 @@
+/*
+ * 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 android.service.textservice;
+
+import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * SpellCheckerService provides an abstract base class for a spell checker.
+ * This class combines a service to the system with the spell checker service interface that
+ * spell checker must implement.
+ */
+public abstract class SpellCheckerService extends Service {
+    private static final String TAG = SpellCheckerService.class.getSimpleName();
+    public static final String SERVICE_INTERFACE = SpellCheckerService.class.getName();
+
+    private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
+
+    /**
+     * Get suggestions for specified text in TextInfo.
+     * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+     * but will be called in series on another thread.
+     * @param textInfo the text metadata
+     * @param suggestionsLimit the number of limit of suggestions returned
+     * @param locale the locale for getting suggestions
+     * @return SuggestionInfo which contains suggestions for textInfo
+     */
+    public abstract SuggestionsInfo getSuggestions(
+            TextInfo textInfo, int suggestionsLimit, String locale);
+
+    /**
+     * A batch process of onGetSuggestions.
+     * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+     * but will be called in series on another thread.
+     * @param textInfos an array of the text metadata
+     * @param locale the locale for getting suggestions
+     * @param suggestionsLimit the number of limit of suggestions returned
+     * @param sequentialWords true if textInfos can be treated as sequential words.
+     * @return an array of SuggestionInfo of onGetSuggestions
+     */
+    public SuggestionsInfo[] getSuggestionsMultiple(
+            TextInfo[] textInfos, String locale, int suggestionsLimit, boolean sequentialWords) {
+        final int length = textInfos.length;
+        final SuggestionsInfo[] retval = new SuggestionsInfo[length];
+        for (int i = 0; i < length; ++i) {
+            retval[i] = getSuggestions(textInfos[i], suggestionsLimit, locale);
+            retval[i].setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
+        }
+        return retval;
+    }
+
+    /**
+     * Request to abort all tasks executed in SpellChecker.
+     * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+     * but will be called in series on another thread.
+     */
+    public void cancel() {}
+
+    /**
+     * Implement to return the implementation of the internal spell checker
+     * service interface. Subclasses should not override.
+     */
+    @Override
+    public final IBinder onBind(final Intent intent) {
+        return mBinder;
+    }
+
+    private static class SpellCheckerSessionImpl extends ISpellCheckerSession.Stub {
+        private final WeakReference<SpellCheckerService> mInternalServiceRef;
+        private final String mLocale;
+        private final ISpellCheckerSessionListener mListener;
+
+        public SpellCheckerSessionImpl(
+                SpellCheckerService service, String locale, ISpellCheckerSessionListener listener) {
+            mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
+            mLocale = locale;
+            mListener = listener;
+        }
+
+        @Override
+        public void getSuggestionsMultiple(
+                TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+            final SpellCheckerService service = mInternalServiceRef.get();
+            if (service == null) return;
+            try {
+                mListener.onGetSuggestions(
+                        service.getSuggestionsMultiple(textInfos, mLocale,
+                                suggestionsLimit, sequentialWords));
+            } catch (RemoteException e) {
+            }
+        }
+
+        @Override
+        public void cancel() {
+            final SpellCheckerService service = mInternalServiceRef.get();
+            if (service == null) return;
+            service.cancel();
+        }
+    }
+
+    private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub {
+        private final WeakReference<SpellCheckerService> mInternalServiceRef;
+
+        public SpellCheckerServiceBinder(SpellCheckerService service) {
+            mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
+        }
+
+        @Override
+        public ISpellCheckerSession getISpellCheckerSession(
+                String locale, ISpellCheckerSessionListener listener) {
+            final SpellCheckerService service = mInternalServiceRef.get();
+            if (service == null) return null;
+            return new SpellCheckerSessionImpl(service, locale, listener);
+        }
+    }
+}
diff --git a/core/java/android/service/textservice/SpellCheckerSession.java b/core/java/android/service/textservice/SpellCheckerSession.java
new file mode 100644
index 0000000..a575220
--- /dev/null
+++ b/core/java/android/service/textservice/SpellCheckerSession.java
@@ -0,0 +1,271 @@
+/*
+ * 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 android.service.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService.
+ */
+public class SpellCheckerSession {
+    private static final String TAG = SpellCheckerSession.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
+
+    private final InternalListener mInternalListener;
+    private final ITextServicesManager mTextServicesManager;
+    private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
+
+    private boolean mIsUsed;
+    private SpellCheckerSessionListener mSpellCheckerSessionListener;
+
+    /** Handler that will execute the main tasks */
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_GET_SUGGESTION_MULTIPLE:
+                    handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj);
+                    break;
+            }
+        }
+    };
+
+    /**
+     * Constructor
+     * @hide
+     */
+    public SpellCheckerSession(ITextServicesManager tsm, SpellCheckerSessionListener listener) {
+        if (listener == null || tsm == null) {
+            throw new NullPointerException();
+        }
+        mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler);
+        mInternalListener = new InternalListener();
+        mTextServicesManager = tsm;
+        mIsUsed = true;
+        mSpellCheckerSessionListener = listener;
+    }
+
+    /**
+     * @return true if the connection to a text service of this session is disconnected and not
+     * alive.
+     */
+    public boolean isSessionDisconnected() {
+        return mSpellCheckerSessionListenerImpl.isDisconnected();
+    }
+
+    /**
+     * Finish this session and allow TextServicesManagerService to disconnect the bound spell
+     * checker.
+     */
+    public void close() {
+        mIsUsed = false;
+        try {
+            mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
+        } catch (RemoteException e) {
+            // do nothing
+        }
+    }
+
+    /**
+     * Get candidate strings for a substring of the specified text.
+     * @param textInfo text metadata for a spell checker
+     * @param suggestionsLimit the number of limit of suggestions returned
+     */
+    public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
+        getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
+    }
+
+    /**
+     * A batch process of getSuggestions
+     * @param textInfos an array of text metadata for a spell checker
+     * @param suggestionsLimit the number of limit of suggestions returned
+     * @param sequentialWords true if textInfos can be treated as sequential words.
+     */
+    public void getSuggestions(
+            TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+        // TODO: Handle multiple words suggestions by using WordBreakIterator
+        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
+                textInfos, suggestionsLimit, sequentialWords);
+    }
+
+    private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) {
+        mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos);
+    }
+
+    private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
+        private static final int TASK_CANCEL = 1;
+        private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
+        private final Queue<SpellCheckerParams> mPendingTasks =
+                new LinkedList<SpellCheckerParams>();
+        private final Handler mHandler;
+
+        private boolean mOpened;
+        private ISpellCheckerSession mISpellCheckerSession;
+
+        public SpellCheckerSessionListenerImpl(Handler handler) {
+            mOpened = false;
+            mHandler = handler;
+        }
+
+        private static class SpellCheckerParams {
+            public final int mWhat;
+            public final TextInfo[] mTextInfos;
+            public final int mSuggestionsLimit;
+            public final boolean mSequentialWords;
+            public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit,
+                    boolean sequentialWords) {
+                mWhat = what;
+                mTextInfos = textInfos;
+                mSuggestionsLimit = suggestionsLimit;
+                mSequentialWords = sequentialWords;
+            }
+        }
+
+        private void processTask(SpellCheckerParams scp) {
+            switch (scp.mWhat) {
+                case TASK_CANCEL:
+                    processCancel();
+                    break;
+                case TASK_GET_SUGGESTIONS_MULTIPLE:
+                    processGetSuggestionsMultiple(scp);
+                    break;
+            }
+        }
+
+        public synchronized void onServiceConnected(ISpellCheckerSession session) {
+            mISpellCheckerSession = session;
+            mOpened = true;
+            if (DBG)
+                Log.d(TAG, "onServiceConnected - Success");
+            while (!mPendingTasks.isEmpty()) {
+                processTask(mPendingTasks.poll());
+            }
+        }
+
+        public void getSuggestionsMultiple(
+                TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+            processOrEnqueueTask(
+                    new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
+                            suggestionsLimit, sequentialWords));
+        }
+
+        public boolean isDisconnected() {
+            return mOpened && mISpellCheckerSession == null;
+        }
+
+        public boolean checkOpenConnection() {
+            if (mISpellCheckerSession != null) {
+                return true;
+            }
+            Log.e(TAG, "not connected to the spellchecker service.");
+            return false;
+        }
+
+        private void processOrEnqueueTask(SpellCheckerParams scp) {
+            if (mISpellCheckerSession == null) {
+                mPendingTasks.offer(scp);
+            } else {
+                processTask(scp);
+            }
+        }
+
+        private void processCancel() {
+            if (!checkOpenConnection()) {
+                return;
+            }
+            try {
+                mISpellCheckerSession.cancel();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to cancel " + e);
+            }
+        }
+
+        private void processGetSuggestionsMultiple(SpellCheckerParams scp) {
+            if (!checkOpenConnection()) {
+                return;
+            }
+            try {
+                mISpellCheckerSession.getSuggestionsMultiple(
+                        scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to get suggestions " + e);
+            }
+        }
+
+        @Override
+        public void onGetSuggestions(SuggestionsInfo[] results) {
+            mHandler.sendMessage(Message.obtain(mHandler, MSG_ON_GET_SUGGESTION_MULTIPLE, results));
+        }
+    }
+
+    /**
+     * Callback for getting results from text services
+     */
+    public interface SpellCheckerSessionListener {
+        /**
+         * Callback for "getSuggestions"
+         * @param results an array of results of getSuggestions
+         */
+        public void onGetSuggestions(SuggestionsInfo[] results);
+    }
+
+    private class InternalListener extends ITextServicesSessionListener.Stub {
+        @Override
+        public void onServiceConnected(ISpellCheckerSession session) {
+            mSpellCheckerSessionListenerImpl.onServiceConnected(session);
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        super.finalize();
+        if (mIsUsed) {
+            Log.e(TAG, "SpellCheckerSession was not finished properly." +
+                    "You should call finishShession() when you finished to use a spell checker.");
+            close();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public ITextServicesSessionListener getTextServicesSessionListener() {
+        return mInternalListener;
+    }
+
+    /**
+     * @hide
+     */
+    public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
+        return mSpellCheckerSessionListenerImpl;
+    }
+}
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index f139372..f2a86c9 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -740,8 +740,8 @@
             limit += total;
 
             // if this is the first read, consume an optional byte order mark (BOM) if it exists
-            if (bufferStartLine == 1 && bufferStartColumn == 1
-                    && limit > 0 && buffer[0] == '\ufeff') {
+                if (bufferStartLine == 1 && bufferStartColumn == 1
+                        && limit > 0 && buffer[0] == '\ufeff') {
                 pos++;
                 bufferStartColumn--;
             }
@@ -852,7 +852,7 @@
 
     private boolean skipTo(String toFind) throws IOException {
         outer:
-        for (; pos + toFind.length() < limit || fillBuffer(toFind.length()); pos++) {
+        for (; pos + toFind.length() <= limit || fillBuffer(toFind.length()); pos++) {
             for (int c = 0; c < toFind.length(); c++) {
                 if (buffer[pos + c] != toFind.charAt(c)) {
                     continue outer;
diff --git a/core/java/android/view/CollapsibleActionView.java b/core/java/android/view/CollapsibleActionView.java
new file mode 100644
index 0000000..ab2365e
--- /dev/null
+++ b/core/java/android/view/CollapsibleActionView.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.view;
+
+import android.view.MenuItem.OnActionExpandListener;
+
+/**
+ * When a {@link View} implements this interface it will receive callbacks
+ * when expanded or collapsed as an action view alongside the optional,
+ * app-specified callbacks to {@link OnActionExpandListener}.
+ *
+ * <p>See {@link MenuItem} for more information about action views.
+ * See {@link android.app.ActionBar} for more information about the action bar.
+ */
+public interface CollapsibleActionView {
+    /**
+     * Called when this view is expanded as an action view.
+     * See {@link MenuItem#expandActionView()}.
+     */
+    public void onActionViewExpanded();
+
+    /**
+     * Called when this view is collapsed as an action view.
+     * See {@link MenuItem#collapseActionView()}.
+     */
+    public void onActionViewCollapsed();
+}
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 4484d59..f4c0249 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -41,15 +41,6 @@
     abstract void end();
 
     /**
-     * Indicates whether this display list can be replayed or not.
-     * 
-     * @return True if the display list can be replayed, false otherwise.
-     * 
-     * @see android.view.HardwareCanvas#drawDisplayList(DisplayList) 
-     */
-    abstract boolean isReady();
-
-    /**
      * Invalidates the display list, indicating that it should be repopulated
      * with new drawing commands prior to being used again. Calling this method
      * causes calls to {@link #isValid()} to return <code>false</code>.
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 80244bb..d22fa6e 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -51,6 +51,7 @@
 
     // The native renderer will be destroyed when this object dies.
     // DO NOT overwrite this reference once it is set.
+    @SuppressWarnings("unused")
     private CanvasFinalizer mFinalizer;
 
     private int mWidth;
@@ -97,12 +98,8 @@
     protected GLES20Canvas(boolean record, boolean translucent) {
         mOpaque = !translucent;
 
-        setupRenderer(record);
-    }
-
-    protected void setupRenderer(boolean record) {
         if (record) {
-            mRenderer = nGetDisplayListRenderer(mRenderer);
+            mRenderer = nCreateDisplayListRenderer();
         } else {
             mRenderer = nCreateRenderer();
         }
@@ -114,43 +111,31 @@
         if (mRenderer == 0) {
             throw new IllegalStateException("Could not create GLES20Canvas renderer");
         } else {
-            mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer);
+            mFinalizer = new CanvasFinalizer(mRenderer);
         }
     }
 
+    protected void resetDisplayListRenderer() {
+        nResetDisplayListRenderer(mRenderer);
+    }
+
     private static native int nCreateRenderer();
     private static native int nCreateLayerRenderer(int layer);
-    private static native int nGetDisplayListRenderer(int renderer);
+    private static native int nCreateDisplayListRenderer();
+    private static native void nResetDisplayListRenderer(int renderer);
     private static native void nDestroyRenderer(int renderer);
 
-    private static class CanvasFinalizer {
-        int mRenderer;
+    private static final class CanvasFinalizer {
+        private final int mRenderer;
 
-        // Factory method returns new instance if old one is null, or old instance
-        // otherwise, destroying native renderer along the way as necessary
-        static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) {
-            if (oldFinalizer == null) {
-                return new CanvasFinalizer(renderer);
-            }
-            oldFinalizer.replaceNativeObject(renderer);
-            return oldFinalizer;
-        }
-
-        private CanvasFinalizer(int renderer) {
+        public CanvasFinalizer(int renderer) {
             mRenderer = renderer;
         }
 
-        private void replaceNativeObject(int newRenderer) {
-            if (mRenderer != 0 && newRenderer != mRenderer) {
-                nDestroyRenderer(mRenderer);
-            }
-            mRenderer = newRenderer;
-        }
-
         @Override
         protected void finalize() throws Throwable {
             try {
-                replaceNativeObject(0);
+                nDestroyRenderer(mRenderer);
             } finally {
                 super.finalize();
             }
@@ -322,11 +307,11 @@
     // Display list
     ///////////////////////////////////////////////////////////////////////////
 
-    int getDisplayList() {
-        return nGetDisplayList(mRenderer);
+    int getDisplayList(int displayList) {
+        return nGetDisplayList(mRenderer, displayList);
     }
 
-    private static native int nGetDisplayList(int renderer);
+    private static native int nGetDisplayList(int renderer, int displayList);
     
     static void destroyDisplayList(int displayList) {
         nDestroyDisplayList(displayList);
@@ -337,7 +322,7 @@
     @Override
     public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
         return nDrawDisplayList(mRenderer,
-                ((GLES20DisplayList) displayList).mNativeDisplayList, width, height, dirty);
+                ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
     }
 
     private static native boolean nDrawDisplayList(int renderer, int displayList,
@@ -345,7 +330,7 @@
 
     @Override
     void outputDisplayList(DisplayList displayList) {
-        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
     }
 
     private static native void nOutputDisplayList(int renderer, int displayList);
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index aeff31f..9e649cea 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -16,52 +16,50 @@
 
 package android.view;
 
-import java.lang.ref.WeakReference;
+import android.graphics.Bitmap;
+
+import java.util.ArrayList;
 
 /**
  * An implementation of display list for OpenGL ES 2.0.
  */
 class GLES20DisplayList extends DisplayList {
-    private GLES20Canvas mCanvas;
+    // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
+    // as the DisplayList is alive.  The Bitmaps are populated by the GLES20RecordingCanvas.
+    final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
 
-    private boolean mStarted = false;
-    private boolean mRecorded = false;
-    private boolean mValid = false;
-
-    int mNativeDisplayList;
-    WeakReference<View> hostView;
+    private GLES20RecordingCanvas mCanvas;
+    private boolean mValid;
 
     // The native display list will be destroyed when this object dies.
     // DO NOT overwrite this reference once it is set.
-    @SuppressWarnings("unused")
     private DisplayListFinalizer mFinalizer;
 
-    public GLES20DisplayList(View view) {
-        hostView = new WeakReference<View>(view);
+    int getNativeDisplayList() {
+        if (!mValid || mFinalizer == null) {
+            throw new IllegalStateException("The display list is not valid.");
+        }
+        return mFinalizer.mNativeDisplayList;
     }
 
     @Override
     HardwareCanvas start() {
-        if (mStarted) {
+        if (mCanvas != null) {
             throw new IllegalStateException("Recording has already started");
         }
 
-        if (mCanvas != null) {
-            ((GLES20RecordingCanvas) mCanvas).reset();
-        } else {
-            mCanvas = new GLES20RecordingCanvas(true);
-        }
-        mStarted = true;
-        mRecorded = false;
-        mValid = true;
-
+        mValid = false;
+        mCanvas = GLES20RecordingCanvas.obtain(this);
+        mCanvas.start();
         return mCanvas;
     }
 
     @Override
     void invalidate() {
-        mStarted = false;
-        mRecorded = false;
+        if (mCanvas != null) {
+            mCanvas.recycle();
+            mCanvas = null;
+        }
         mValid = false;
     }
 
@@ -73,48 +71,28 @@
     @Override
     void end() {
         if (mCanvas != null) {
-            mStarted = false;
-            mRecorded = true;
-
-            mNativeDisplayList = mCanvas.getDisplayList();
-            mFinalizer = DisplayListFinalizer.getFinalizer(mFinalizer, mNativeDisplayList);
+            if (mFinalizer != null) {
+                mCanvas.end(mFinalizer.mNativeDisplayList);
+            } else {
+                mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
+            }
+            mCanvas.recycle();
+            mCanvas = null;
+            mValid = true;
         }
     }
 
-    @Override
-    boolean isReady() {
-        return !mStarted && mRecorded;
-    }
-
     private static class DisplayListFinalizer {
-        int mNativeDisplayList;
+        final int mNativeDisplayList;
 
-        // Factory method returns new instance if old one is null, or old instance
-        // otherwise, destroying native display list along the way as necessary
-        static DisplayListFinalizer getFinalizer(DisplayListFinalizer oldFinalizer,
-                int nativeDisplayList) {
-            if (oldFinalizer == null) {
-                return new DisplayListFinalizer(nativeDisplayList);
-            }
-            oldFinalizer.replaceNativeObject(nativeDisplayList);
-            return oldFinalizer;
-        }
-
-        private DisplayListFinalizer(int nativeDisplayList) {
+        public DisplayListFinalizer(int nativeDisplayList) {
             mNativeDisplayList = nativeDisplayList;
         }
 
-        private void replaceNativeObject(int newNativeDisplayList) {
-            if (mNativeDisplayList != 0 && mNativeDisplayList != newNativeDisplayList) {
-                GLES20Canvas.destroyDisplayList(mNativeDisplayList);
-            }
-            mNativeDisplayList = newNativeDisplayList;
-        }
-
         @Override
         protected void finalize() throws Throwable {
             try {
-                replaceNativeObject(0);
+                GLES20Canvas.destroyDisplayList(mNativeDisplayList);
             } finally {
                 super.finalize();
             }
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index ec94fe7..078222b 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -24,8 +24,10 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Shader;
-
-import java.util.ArrayList;
+import android.util.Pool;
+import android.util.Poolable;
+import android.util.PoolableManager;
+import android.util.Pools;
 
 /**
  * An implementation of a GL canvas that records drawing operations.
@@ -33,62 +35,94 @@
  * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
  * the DisplayList is still holding a native reference to the memory.
  */
-class GLES20RecordingCanvas extends GLES20Canvas {
-    // These lists ensure that any Bitmaps recorded by a DisplayList are kept alive as long
-    // as the DisplayList is alive.
-    @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
-    private final ArrayList<Bitmap> mBitmaps = new ArrayList<Bitmap>(5);
+class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
+    // The recording canvas pool should be large enough to handle a deeply nested
+    // view hierarchy because display lists are generated recursively.
+    private static final int POOL_LIMIT = 50;
 
-    GLES20RecordingCanvas(boolean translucent) {
-        super(true, translucent);
+    private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
+            Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
+                public GLES20RecordingCanvas newInstance() {
+                    return new GLES20RecordingCanvas();
+                }
+                @Override
+                public void onAcquired(GLES20RecordingCanvas element) {
+                }
+                @Override
+                public void onReleased(GLES20RecordingCanvas element) {
+                }
+            }, POOL_LIMIT));
+
+    private GLES20RecordingCanvas mNextPoolable;
+    private boolean mIsPooled;
+
+    private GLES20DisplayList mDisplayList;
+
+    private GLES20RecordingCanvas() {
+        super(true /*record*/, true /*translucent*/);
+    }
+
+    static GLES20RecordingCanvas obtain(GLES20DisplayList displayList) {
+        GLES20RecordingCanvas canvas = sPool.acquire();
+        canvas.mDisplayList = displayList;
+        return canvas;
+    }
+
+    void recycle() {
+        mDisplayList = null;
+        resetDisplayListRenderer();
+        sPool.release(this);
+    }
+
+    void start() {
+        mDisplayList.mBitmaps.clear();
+    }
+
+    int end(int nativeDisplayList) {
+        return getDisplayList(nativeDisplayList);
     }
 
     private void recordShaderBitmap(Paint paint) {
         if (paint != null) {
             final Shader shader = paint.getShader();
             if (shader instanceof BitmapShader) {
-                mBitmaps.add(((BitmapShader) shader).mBitmap);
+                mDisplayList.mBitmaps.add(((BitmapShader) shader).mBitmap);
             }
         }
     }
 
-    void reset() {
-        mBitmaps.clear();
-        setupRenderer(true);
-    }
-
     @Override
     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
         super.drawPatch(bitmap, chunks, dst, paint);
-        mBitmaps.add(bitmap);
+        mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
         super.drawBitmap(bitmap, left, top, paint);
-        mBitmaps.add(bitmap);
+        mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
         super.drawBitmap(bitmap, matrix, paint);
-        mBitmaps.add(bitmap);
+        mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
         super.drawBitmap(bitmap, src, dst, paint);
-        mBitmaps.add(bitmap);
+        mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
         super.drawBitmap(bitmap, src, dst, paint);
-        mBitmaps.add(bitmap);
+        mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
 
@@ -111,7 +145,7 @@
             int vertOffset, int[] colors, int colorOffset, Paint paint) {
         super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
                 paint);
-        mBitmaps.add(bitmap);
+        mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
 
@@ -270,4 +304,24 @@
                 colorOffset, indices, indexOffset, indexCount, paint);
         recordShaderBitmap(paint);
     }
+
+    @Override
+    public GLES20RecordingCanvas getNextPoolable() {
+        return mNextPoolable;
+    }
+
+    @Override
+    public void setNextPoolable(GLES20RecordingCanvas element) {
+        mNextPoolable = element;
+    }
+
+    @Override
+    public boolean isPooled() {
+        return mIsPooled;
+    }
+
+    @Override
+    public void setPooled(boolean isPooled) {
+        mIsPooled = isPooled;
+    }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b865b50..503b54b 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -189,7 +189,7 @@
      * 
      * @return A new display list.
      */
-    abstract DisplayList createDisplayList(View v);
+    abstract DisplayList createDisplayList();
 
     /**
      * Creates a new hardware layer. A hardware layer built by calling this
@@ -852,8 +852,8 @@
         }
 
         @Override
-        DisplayList createDisplayList(View v) {
-            return new GLES20DisplayList(v);
+        DisplayList createDisplayList() {
+            return new GLES20DisplayList();
         }
 
         @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0108ecf..ecb391d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9099,7 +9099,10 @@
         mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED;
     }
 
-    private void resolvePadding() {
+    /**
+     * @hide
+     */
+    protected void resolvePadding() {
         // If the user specified the absolute padding (either with android:padding or
         // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
         // use the default padding or the padding from the background drawable
@@ -9830,7 +9833,7 @@
             // we copy in child display lists into ours in drawChild()
             mRecreateDisplayList = true;
             if (mDisplayList == null) {
-                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(this);
+                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
                 // If we're creating a new display list, make sure our parent gets invalidated
                 // since they will need to recreate their display list to account for this
                 // new child display list.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 3798c9d..4acf48c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -25,6 +25,7 @@
 import android.os.Environment;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
@@ -36,7 +37,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -50,6 +51,9 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -426,22 +430,22 @@
      * and obtain the traces. Both methods must be invoked on the
      * same thread.
      * 
-     * @param traceFile The path where to write the looper traces
-     * 
-     * @see #stopLooperProfiling() 
+     * @hide
      */
-    public static void startLooperProfiling(File traceFile) {
+    public static void startLooperProfiling(String path, FileDescriptor fileDescriptor) {
         if (sLooperProfilerStorage.get() == null) {
-            LooperProfiler profiler = new LooperProfiler(traceFile);
+            LooperProfiler profiler = new LooperProfiler(path, fileDescriptor);
             sLooperProfilerStorage.set(profiler);
             Looper.myLooper().setMessageLogging(profiler);
         }
-    }
+    }    
 
     /**
      * Stops profiling the looper associated with the current thread.
      * 
-     * @see #startLooperProfiling(java.io.File) 
+     * @see #startLooperProfiling(String, java.io.FileDescriptor) 
+     * 
+     * @hide
      */
     public static void stopLooperProfiling() {
         LooperProfiler profiler = sLooperProfilerStorage.get();
@@ -453,21 +457,33 @@
     }
 
     private static class LooperProfiler implements Looper.Profiler, Printer {
-        private static final int LOOPER_PROFILER_VERSION = 1;
-
         private static final String LOG_TAG = "LooperProfiler";
 
+        private static final int TRACE_VERSION_NUMBER = 3;
+        private static final int ACTION_EXIT_METHOD = 0x1;
+        private static final int HEADER_SIZE = 32;
+        private static final String HEADER_MAGIC = "SLOW";
+        private static final short HEADER_RECORD_SIZE = (short) 14;
+
         private final long mTraceWallStart;
         private final long mTraceThreadStart;
         
         private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512);
-        private final File mTraceFile;
 
-        private final HashMap<String, Short> mTraceNames = new HashMap<String, Short>(32);
-        private short mTraceId = 0;
+        private final HashMap<String, Integer> mTraceNames = new HashMap<String, Integer>(32);
+        private int mTraceId = 0;
 
-        LooperProfiler(File traceFile) {
-            mTraceFile = traceFile;
+        private final String mPath;
+        private ParcelFileDescriptor mFileDescriptor;
+
+        LooperProfiler(String path, FileDescriptor fileDescriptor) {
+            mPath = path;
+            try {
+                mFileDescriptor = ParcelFileDescriptor.dup(fileDescriptor);
+            } catch (IOException e) {
+                Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
+                throw new RuntimeException(e);
+            }
             mTraceWallStart = SystemClock.currentTimeMicro();
             mTraceThreadStart = SystemClock.currentThreadTimeMicro();            
         }
@@ -490,11 +506,11 @@
             mTraces.add(entry);
         }
 
-        private short getTraceId(Message message) {
+        private int getTraceId(Message message) {
             String name = message.getTarget().getMessageName(message);
-            Short traceId = mTraceNames.get(name);
+            Integer traceId = mTraceNames.get(name);
             if (traceId == null) {
-                traceId = mTraceId++;
+                traceId = mTraceId++ << 4;
                 mTraceNames.put(name, traceId);
             }
             return traceId;
@@ -507,62 +523,135 @@
                 public void run() {
                     saveTraces();
                 }
-            }, "LooperProfiler[" + mTraceFile + "]").start();
+            }, "LooperProfiler[" + mPath + "]").start();
         }
 
         private void saveTraces() {
-            FileOutputStream fos;
-            try {
-                fos = new FileOutputStream(mTraceFile);
-            } catch (FileNotFoundException e) {
-                Log.e(LOG_TAG, "Could not open trace file: " + mTraceFile);
-                return;
-            }
-
+            FileOutputStream fos = new FileOutputStream(mFileDescriptor.getFileDescriptor());
             DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
 
             try {
-                out.writeInt(LOOPER_PROFILER_VERSION);
-                out.writeLong(mTraceWallStart);
-                out.writeLong(mTraceThreadStart);
+                writeHeader(out, mTraceWallStart, mTraceNames, mTraces);
+                out.flush();
 
-                out.writeInt(mTraceNames.size());
-                for (Map.Entry<String, Short> entry : mTraceNames.entrySet()) {
-                    saveTraceName(entry.getKey(), entry.getValue(), out);
-                }
+                writeTraces(fos, out.size(), mTraceWallStart, mTraceThreadStart, mTraces);
 
-                out.writeInt(mTraces.size());
-                for (Entry entry : mTraces) {
-                    saveTrace(entry, out);
-                }
-
-                Log.d(LOG_TAG, "Looper traces ready: " + mTraceFile);
+                Log.d(LOG_TAG, "Looper traces ready: " + mPath);
             } catch (IOException e) {
-                Log.e(LOG_TAG, "Could not write trace file: ", e);
+                Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
             } finally {
                 try {
                     out.close();
                 } catch (IOException e) {
-                    // Ignore
+                    Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
+                }
+                try {
+                    mFileDescriptor.close();
+                } catch (IOException e) {
+                    Log.e(LOG_TAG, "Could not write trace file " + mPath, e);
                 }
             }
         }
-
-        private void saveTraceName(String name, short id, DataOutputStream out) throws IOException {
-            out.writeShort(id);
-            out.writeUTF(name);
+        
+        private static void writeTraces(FileOutputStream out, long offset, long wallStart,
+                long threadStart, ArrayList<Entry> entries) throws IOException {
+    
+            FileChannel channel = out.getChannel();
+    
+            // Header
+            ByteBuffer buffer = ByteBuffer.allocateDirect(HEADER_SIZE);
+            buffer.put(HEADER_MAGIC.getBytes());
+            buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
+            buffer.putShort((short) TRACE_VERSION_NUMBER);    // version
+            buffer.putShort((short) HEADER_SIZE);             // offset to data
+            buffer.putLong(wallStart);                        // start time in usec
+            buffer.putShort(HEADER_RECORD_SIZE);              // size of a record in bytes
+            // padding to 32 bytes
+            for (int i = 0; i < HEADER_SIZE - 18; i++) {
+                buffer.put((byte) 0);
+            }
+    
+            buffer.flip();
+            channel.position(offset).write(buffer);
+            
+            buffer = ByteBuffer.allocateDirect(14).order(ByteOrder.LITTLE_ENDIAN);
+            for (Entry entry : entries) {
+                buffer.putShort((short) 1);   // we simulate only one thread
+                buffer.putInt(entry.traceId); // entering method
+                buffer.putInt((int) (entry.threadStart - threadStart));
+                buffer.putInt((int) (entry.wallStart - wallStart));
+    
+                buffer.flip();
+                channel.write(buffer);
+                buffer.clear();
+    
+                buffer.putShort((short) 1);
+                buffer.putInt(entry.traceId | ACTION_EXIT_METHOD); // exiting method
+                buffer.putInt((int) (entry.threadStart + entry.threadTime - threadStart));
+                buffer.putInt((int) (entry.wallStart + entry.wallTime - wallStart));
+    
+                buffer.flip();
+                channel.write(buffer);
+                buffer.clear();
+            }
+    
+            channel.close();
         }
+    
+        private static void writeHeader(DataOutputStream out, long start,
+                HashMap<String, Integer> names, ArrayList<Entry> entries) throws IOException {
+    
+            Entry last = entries.get(entries.size() - 1);
+            long wallTotal = (last.wallStart + last.wallTime) - start;
+    
+            startSection("version", out);
+            addValue(null, Integer.toString(TRACE_VERSION_NUMBER), out);
+            addValue("data-file-overflow", "false", out);
+            addValue("clock", "dual", out);
+            addValue("elapsed-time-usec", Long.toString(wallTotal), out);
+            addValue("num-method-calls", Integer.toString(entries.size()), out);
+            addValue("clock-call-overhead-nsec", "1", out);
+            addValue("vm", "dalvik", out);
+    
+            startSection("threads", out);
+            addThreadId(1, "main", out);
+    
+            startSection("methods", out);
+            addMethods(names, out);
+    
+            startSection("end", out);
+        }
+    
+        private static void addMethods(HashMap<String, Integer> names, DataOutputStream out)
+                throws IOException {
+    
+            for (Map.Entry<String, Integer> name : names.entrySet()) {
+                out.writeBytes(String.format("0x%08x\tEventQueue\t%s\t()V\tLooper\t-2\n",
+                        name.getValue(), name.getKey()));
+            }
+        }
+    
+        private static void addThreadId(int id, String name, DataOutputStream out)
+                throws IOException {
 
-        private void saveTrace(Entry entry, DataOutputStream out) throws IOException {
-            out.writeShort(entry.traceId);
-            out.writeLong(entry.wallStart);
-            out.writeLong(entry.wallTime);
-            out.writeLong(entry.threadStart);
-            out.writeLong(entry.threadTime);
+            out.writeBytes(Integer.toString(id) + '\t' + name + '\n');
+        }
+    
+        private static void addValue(String name, String value, DataOutputStream out)
+                throws IOException {
+    
+            if (name != null) {
+                out.writeBytes(name + "=");
+            }
+            out.writeBytes(value + '\n');
+        }
+    
+        private static void startSection(String name, DataOutputStream out) throws IOException {
+            out.writeBytes("*" + name + '\n');
         }
 
         static class Entry {
-            short traceId;
+            int traceId;
             long wallStart;
             long wallTime;
             long threadStart;
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.aidl b/core/java/android/view/textservice/SpellCheckerInfo.aidl
new file mode 100644
index 0000000..eb5dfcc
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.textservice;
+
+parcelable SpellCheckerInfo;
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
new file mode 100644
index 0000000..1205adf
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -0,0 +1,112 @@
+/*
+ * 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 android.view.textservice;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class is used to specify meta information of an spell checker.
+ */
+public final class SpellCheckerInfo implements Parcelable {
+    private final ResolveInfo mService;
+    private final String mId;
+
+    /**
+     * Constructor.
+     * @hide
+     */
+    public SpellCheckerInfo(Context context, ResolveInfo service) {
+        mService = service;
+        ServiceInfo si = service.serviceInfo;
+        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+    }
+
+    /**
+     * Constructor.
+     * @hide
+     */
+    public SpellCheckerInfo(Parcel source) {
+        mId = source.readString();
+        mService = ResolveInfo.CREATOR.createFromParcel(source);
+    }
+
+    /**
+     * Return a unique ID for this spell checker.  The ID is generated from
+     * the package and class name implementing the method.
+     */
+    public String getId() {
+        return mId;
+    }
+
+
+    /**
+     * Return the component of the service that implements.
+     */
+    public ComponentName getComponent() {
+        return new ComponentName(
+                mService.serviceInfo.packageName, mService.serviceInfo.name);
+    }
+
+    /**
+     * Return the .apk package that implements this input method.
+     */
+    public String getPackageName() {
+        return mService.serviceInfo.packageName;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+        mService.writeToParcel(dest, flags);
+    }
+
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<SpellCheckerInfo> CREATOR
+            = new Parcelable.Creator<SpellCheckerInfo>() {
+        @Override
+        public SpellCheckerInfo createFromParcel(Parcel source) {
+            return new SpellCheckerInfo(source);
+        }
+
+        @Override
+        public SpellCheckerInfo[] newArray(int size) {
+            return new SpellCheckerInfo[size];
+        }
+    };
+
+    /**
+     * Used to make this class parcelable.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.aidl b/core/java/android/view/textservice/SuggestionsInfo.aidl
new file mode 100644
index 0000000..66e20d2
--- /dev/null
+++ b/core/java/android/view/textservice/SuggestionsInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.textservice;
+
+parcelable SuggestionsInfo;
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
new file mode 100644
index 0000000..b0ccbea
--- /dev/null
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -0,0 +1,176 @@
+/*
+ * 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 android.view.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains a metadata of suggestions from the text service
+ */
+public final class SuggestionsInfo implements Parcelable {
+    /**
+     * Flag of the attributes of the suggestions that can be obtained by
+     * {@link #getSuggestionsAttributes}: this tells that the requested word was found
+     * in the dictionary in the text service.
+     */
+    public static final int RESULT_ATTR_IN_THE_DICTIONARY = 0x0001;
+    /** Flag of the attributes of the suggestions that can be obtained by
+     * {@link #getSuggestionsAttributes}: this tells that there are one or more suggestions
+     * available for the requested word.  This doesn't necessarily mean that the suggestions
+     * are actually in this SuggestionsInfo.  For instance, the caller could have been asked to
+     * limit the maximum number of suggestions returned.
+     */
+    public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 0x0002;
+    /**
+     * Flag of the attributes of the suggestions that can be obtained by
+     * {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
+     * word looks a typo.
+     */
+    public static final int RESULT_ATTR_LOOKS_TYPO = 0x0004;
+    private final int mSuggestionsAttributes;
+    private final String[] mSuggestions;
+    private int mCookie;
+    private int mSequence;
+
+    /**
+     * Constructor.
+     * @param suggestionsAttributes from the text service
+     * @param suggestions from the text service
+     */
+    public SuggestionsInfo(int suggestionsAttributes, String[] suggestions) {
+        if (suggestions == null) {
+            throw new NullPointerException();
+        }
+        mSuggestionsAttributes = suggestionsAttributes;
+        mSuggestions = suggestions;
+        mCookie = 0;
+        mSequence = 0;
+    }
+
+    /**
+     * Constructor.
+     * @param suggestionsAttributes from the text service
+     * @param suggestions from the text service
+     * @param cookie the cookie of the input TextInfo
+     * @param sequence the cookie of the input TextInfo
+     */
+    public SuggestionsInfo(
+            int suggestionsAttributes, String[] suggestions, int cookie, int sequence) {
+        if (suggestions == null) {
+            throw new NullPointerException();
+        }
+        mSuggestionsAttributes = suggestionsAttributes;
+        mSuggestions = suggestions;
+        mCookie = cookie;
+        mSequence = sequence;
+    }
+
+    public SuggestionsInfo(Parcel source) {
+        mSuggestionsAttributes = source.readInt();
+        mSuggestions = source.readStringArray();
+        mCookie = source.readInt();
+        mSequence = source.readInt();
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSuggestionsAttributes);
+        dest.writeStringArray(mSuggestions);
+        dest.writeInt(mCookie);
+        dest.writeInt(mSequence);
+    }
+
+    /**
+     * Set the cookie and the sequence of SuggestionsInfo which are set to TextInfo from a client
+     * application
+     * @param cookie the cookie of an input TextInfo
+     * @param sequence the cookie of an input TextInfo
+     */
+    public void setCookieAndSequence(int cookie, int sequence) {
+        mCookie = cookie;
+        mSequence = sequence;
+    }
+
+    /**
+     * @return the cookie which may be set by a client application
+     */
+    public int getCookie() {
+        return mCookie;
+    }
+
+    /**
+     * @return the sequence which may be set by a client application
+     */
+    public int getSequence() {
+        return mSequence;
+    }
+
+    /**
+     * @return the attributes of suggestions. This includes whether the spell checker has the word
+     * in its dictionary or not and whether the spell checker has confident suggestions for the
+     * word or not.
+     */
+    public int getSuggestionsAttributes() {
+        return mSuggestionsAttributes;
+    }
+
+    /**
+     * @return the count of suggestions
+     */
+    public int getSuggestionsCount() {
+        return mSuggestions.length;
+    }
+
+    /**
+     * @param i the id of suggestions
+     * @return the suggestion at the specified id
+     */
+    public String getSuggestionAt(int i) {
+        return mSuggestions[i];
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<SuggestionsInfo> CREATOR
+            = new Parcelable.Creator<SuggestionsInfo>() {
+        @Override
+        public SuggestionsInfo createFromParcel(Parcel source) {
+            return new SuggestionsInfo(source);
+        }
+
+        @Override
+        public SuggestionsInfo[] newArray(int size) {
+            return new SuggestionsInfo[size];
+        }
+    };
+
+    /**
+     * Used to make this class parcelable.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/textservice/TextInfo.aidl b/core/java/android/view/textservice/TextInfo.aidl
new file mode 100644
index 0000000..d231d76
--- /dev/null
+++ b/core/java/android/view/textservice/TextInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.textservice;
+
+parcelable TextInfo;
diff --git a/core/java/android/view/textservice/TextInfo.java b/core/java/android/view/textservice/TextInfo.java
new file mode 100644
index 0000000..b534eb0
--- /dev/null
+++ b/core/java/android/view/textservice/TextInfo.java
@@ -0,0 +1,117 @@
+/*
+ * 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 android.view.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * This class contains a metadata of the input of TextService
+ */
+public final class TextInfo implements Parcelable {
+    private final String mText;
+    private final int mCookie;
+    private final int mSequence;
+
+    /**
+     * Constructor.
+     * @param text the text which will be input to TextService
+     */
+    public TextInfo(String text) {
+        this(text, 0, 0);
+    }
+
+    /**
+     * Constructor.
+     * @param text the text which will be input to TextService
+     * @param cookie the cookie for this TextInfo
+     * @param sequence the sequence number for this TextInfo
+     */
+    public TextInfo(String text, int cookie, int sequence) {
+        if (TextUtils.isEmpty(text)) {
+            throw new IllegalArgumentException(text);
+        }
+        mText = text;
+        mCookie = cookie;
+        mSequence = sequence;
+    }
+
+    public TextInfo(Parcel source) {
+        mText = source.readString();
+        mCookie = source.readInt();
+        mSequence = source.readInt();
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mText);
+        dest.writeInt(mCookie);
+        dest.writeInt(mSequence);
+    }
+
+    /**
+     * @return the text which is an input of a text service
+     */
+    public String getText() {
+        return mText;
+    }
+
+    /**
+     * @return the cookie of TextInfo
+     */
+    public int getCookie() {
+        return mCookie;
+    }
+
+    /**
+     * @return the sequence of TextInfo
+     */
+    public int getSequence() {
+        return mSequence;
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<TextInfo> CREATOR
+            = new Parcelable.Creator<TextInfo>() {
+        @Override
+        public TextInfo createFromParcel(Parcel source) {
+            return new TextInfo(source);
+        }
+
+        @Override
+        public TextInfo[] newArray(int size) {
+            return new TextInfo[size];
+        }
+    };
+
+    /**
+     * Used to make this class parcelable.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
new file mode 100644
index 0000000..6fa7e4d
--- /dev/null
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -0,0 +1,106 @@
+/*
+ * 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 android.view.textservice;
+
+import com.android.internal.textservice.ITextServicesManager;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.textservice.SpellCheckerInfo;
+import android.service.textservice.SpellCheckerSession;
+import android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener;
+
+import java.util.Locale;
+
+/**
+ * System API to the overall text services, which arbitrates interaction between applications
+ * and text services. You can retrieve an instance of this interface with
+ * {@link Context#getSystemService(String) Context.getSystemService()}.
+ *
+ * The user can change the current text services in Settings. And also applications can specify
+ * the target text services.
+ */
+public final class TextServicesManager {
+    private static final String TAG = TextServicesManager.class.getSimpleName();
+
+    private static TextServicesManager sInstance;
+    private static ITextServicesManager sService;
+
+    private TextServicesManager() {
+        if (sService == null) {
+            IBinder b = ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+            sService = ITextServicesManager.Stub.asInterface(b);
+        }
+    }
+
+    /**
+     * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist.
+     * @hide
+     */
+    public static TextServicesManager getInstance() {
+        synchronized (TextServicesManager.class) {
+            if (sInstance != null) {
+                return sInstance;
+            }
+            sInstance = new TextServicesManager();
+        }
+        return sInstance;
+    }
+
+
+    /**
+     * Get the current spell checker service info for the specified locale.
+     * @param locale locale of a spell checker
+     * @return SpellCheckerInfo for the specified locale.
+     */
+    // TODO: Add a method to get enabled spell checkers.
+    public SpellCheckerInfo getCurrentSpellChecker(Locale locale) {
+        if (locale == null) {
+            throw new NullPointerException("locale is null");
+        }
+        try {
+            return sService.getCurrentSpellChecker(locale.toString());
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Get a spell checker session for a specified spell checker
+     * @param info SpellCheckerInfo of the spell checker
+     * @param locale the locale for the spell checker
+     * @param listener a spell checker session lister for getting results from a spell checker.
+     * @return the spell checker session of the spell checker
+     */
+    public SpellCheckerSession newSpellCheckerSession(
+            SpellCheckerInfo info, Locale locale, SpellCheckerSessionListener listener) {
+        if (info == null || locale == null || listener == null) {
+            throw new NullPointerException();
+        }
+        final SpellCheckerSession session = new SpellCheckerSession(sService, listener);
+        try {
+            sService.getSpellCheckerService(
+                    info, locale.toString(), session.getTextServicesSessionListener(),
+                    session.getSpellCheckerSessionListener());
+        } catch (RemoteException e) {
+            return null;
+        }
+        return session;
+    }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 73db03e..6a3b2ff 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -9119,20 +9119,12 @@
         return nativeTileProfilingNumTilesInFrame(frame);
     }
     /** @hide only used by profiling tests */
-    public int tileProfilingGetX(int frame, int tile) {
-        return nativeTileProfilingGetX(frame, tile);
+    public int tileProfilingGetInt(int frame, int tile, String key) {
+        return nativeTileProfilingGetInt(frame, tile, key);
     }
     /** @hide only used by profiling tests */
-    public int tileProfilingGetY(int frame, int tile) {
-        return nativeTileProfilingGetY(frame, tile);
-    }
-    /** @hide only used by profiling tests */
-    public boolean tileProfilingGetReady(int frame, int tile) {
-        return nativeTileProfilingGetReady(frame, tile);
-    }
-    /** @hide only used by profiling tests */
-    public int tileProfilingGetLevel(int frame, int tile) {
-        return nativeTileProfilingGetLevel(frame, tile);
+    public float tileProfilingGetFloat(int frame, int tile, String key) {
+        return nativeTileProfilingGetFloat(frame, tile, key);
     }
 
     private native int nativeCacheHitFramePointer();
@@ -9262,10 +9254,8 @@
     private native void     nativeTileProfilingClear();
     private native int      nativeTileProfilingNumFrames();
     private native int      nativeTileProfilingNumTilesInFrame(int frame);
-    private native int      nativeTileProfilingGetX(int frame, int tile);
-    private native int      nativeTileProfilingGetY(int frame, int tile);
-    private native boolean  nativeTileProfilingGetReady(int frame, int tile);
-    private native int      nativeTileProfilingGetLevel(int frame, int tile);
+    private native int      nativeTileProfilingGetInt(int frame, int tile, String key);
+    private native float    nativeTileProfilingGetFloat(int frame, int tile, String key);
     // Never call this version except by updateCachedTextfield(String) -
     // we always want to pass in our generation number.
     private native void     nativeUpdateCachedTextfield(String updatedText,
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index d7a2526..8d8023b 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1069,6 +1069,15 @@
                                 + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
                                 + " obj=" + msg.obj);
                     }
+                    if (mWebView == null
+                            && msg.what != EventHub.RESUME_TIMERS
+                            && msg.what != EventHub.PAUSE_TIMERS) {
+                        if (DebugFlags.WEB_VIEW_CORE) {
+                            Log.v(LOGTAG, "Rejecting message " + msg.what
+                                    + " because we are destroyed");
+                        }
+                        return;
+                    }
                     switch (msg.what) {
                         case WEBKIT_DRAW:
                             webkitDraw();
@@ -1757,30 +1766,17 @@
     }
 
     /**
-     * Removes pending messages and trigger a DESTROY message to send to
-     * WebCore.
+     * Sends a DESTROY message to WebCore.
      * Called from UI thread.
      */
     void destroy() {
-        // We don't want anyone to post a message between removing pending
-        // messages and sending the destroy message.
         synchronized (mEventHub) {
-            // RESUME_TIMERS and PAUSE_TIMERS are per process base. They need to
-            // be preserved even the WebView is destroyed.
-            // Note: we should not have more than one RESUME_TIMERS/PAUSE_TIMERS
-            boolean hasResume = mEventHub.hasMessages(EventHub.RESUME_TIMERS);
-            boolean hasPause = mEventHub.hasMessages(EventHub.PAUSE_TIMERS);
-            mEventHub.removeMessages();
+            // Do not call removeMessages as then we risk removing PAUSE_TIMERS
+            // or RESUME_TIMERS messages, which we must still handle as they
+            // are per process. DESTROY will instead trigger a white list in
+            // mEventHub, skipping any remaining messages in the queue
             mEventHub.sendMessageAtFrontOfQueue(
                     Message.obtain(null, EventHub.DESTROY));
-            if (hasPause) {
-                mEventHub.sendMessageAtFrontOfQueue(
-                        Message.obtain(null, EventHub.PAUSE_TIMERS));
-            }
-            if (hasResume) {
-                mEventHub.sendMessageAtFrontOfQueue(
-                        Message.obtain(null, EventHub.RESUME_TIMERS));
-            }
             mEventHub.blockMessages();
         }
     }
@@ -2113,13 +2109,17 @@
 
     // called from JNI or WebView thread
     /* package */ void contentDraw() {
-        // don't update the Picture until we have an initial width and finish
-        // the first layout
-        if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) {
-            return;
-        }
-        // only fire an event if this is our first request
         synchronized (this) {
+            if (mWebView == null || mBrowserFrame == null) {
+                // We were destroyed
+                return;
+            }
+            // don't update the Picture until we have an initial width and finish
+            // the first layout
+            if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) {
+                return;
+            }
+            // only fire an event if this is our first request
             if (mDrawIsScheduled) return;
             mDrawIsScheduled = true;
             if (mDrawIsPaused) return;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 8f8c1d0..b7c1687 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4638,9 +4638,6 @@
                             childrenTop += getVerticalFadingEdgeLength();
                         }
                     }
-                    // Don't ever focus a disabled item.
-                    if (!mAdapter.isEnabled(i)) continue;
-
                     if (top >= childrenTop) {
                         // Found a view whose top is fully visisble
                         selectedPos = firstPosition + i;
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 49616cc..f3a6da7 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -39,8 +39,9 @@
     private boolean mChecked;
     private int mCheckMarkResource;
     private Drawable mCheckMarkDrawable;
-    private int mBasePaddingRight;
+    private int mBasePadding;
     private int mCheckMarkWidth;
+    private boolean mNeedRequestlayout;
 
     private static final int[] CHECKED_STATE_SET = {
         R.attr.state_checked
@@ -123,6 +124,7 @@
             mCheckMarkDrawable.setCallback(null);
             unscheduleDrawable(mCheckMarkDrawable);
         }
+        mNeedRequestlayout = (d != mCheckMarkDrawable);
         if (d != null) {
             d.setCallback(this);
             d.setVisible(getVisibility() == VISIBLE, false);
@@ -130,19 +132,35 @@
             setMinHeight(d.getIntrinsicHeight());
             
             mCheckMarkWidth = d.getIntrinsicWidth();
-            mUserPaddingRight = mCheckMarkWidth + mBasePaddingRight;
             d.setState(getDrawableState());
         } else {
-            mUserPaddingRight = mBasePaddingRight;
+            mCheckMarkWidth = 0;
         }
         mCheckMarkDrawable = d;
-        requestLayout();
+        // Do padding resolution. This will call setPadding() and do a requestLayout() if needed.
+        resolvePadding();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    protected void resolvePadding() {
+        super.resolvePadding();
+        int newPadding = (mCheckMarkDrawable != null) ?
+                mCheckMarkWidth + mBasePadding : mBasePadding;
+        mNeedRequestlayout |= (mPaddingRight != newPadding);
+        mPaddingRight = newPadding;
+        if (mNeedRequestlayout) {
+            requestLayout();
+            mNeedRequestlayout = false;
+        }
     }
     
     @Override
     public void setPadding(int left, int top, int right, int bottom) {
         super.setPadding(left, top, right, bottom);
-        mBasePaddingRight = mUserPaddingRight;
+        mBasePadding = mPaddingRight;
     }
 
     @Override
@@ -167,9 +185,9 @@
             
             int right = getWidth();
             checkMarkDrawable.setBounds(
-                    right - mUserPaddingRight,
+                    right - mPaddingRight,
                     y, 
-                    right - mUserPaddingRight + mCheckMarkWidth,
+                    right - mPaddingRight + mCheckMarkWidth,
                     y + height);
             checkMarkDrawable.draw(canvas);
         }
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
new file mode 100644
index 0000000..ff00492
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+/**
+ * Public interface to the global spell checker.
+ * @hide
+ */
+interface ISpellCheckerService {
+    ISpellCheckerSession getISpellCheckerSession(
+            String locale, ISpellCheckerSessionListener listener);
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
new file mode 100644
index 0000000..79e43510c0
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.internal.textservice;
+
+import android.view.textservice.TextInfo;
+
+/**
+ * @hide
+ */
+oneway interface ISpellCheckerSession {
+    void getSuggestionsMultiple(
+            in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
+    void cancel();
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
new file mode 100644
index 0000000..796b06e
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.internal.textservice;
+
+import android.view.textservice.SuggestionsInfo;
+
+/**
+ * @hide
+ */
+oneway interface ISpellCheckerSessionListener {
+    void onGetSuggestions(in SuggestionsInfo[] results);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
new file mode 100644
index 0000000..ad0c1ff
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.content.ComponentName;
+import android.view.textservice.SpellCheckerInfo;
+
+/**
+ * Interface to the text service manager.
+ * @hide
+ */
+interface ITextServicesManager {
+    SpellCheckerInfo getCurrentSpellChecker(String locale);
+    oneway void getSpellCheckerService(in SpellCheckerInfo info, in String locale,
+            in ITextServicesSessionListener tsListener,
+            in ISpellCheckerSessionListener scListener);
+    oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
new file mode 100644
index 0000000..ecb6cd0
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+
+import android.view.textservice.SpellCheckerInfo;
+
+/**
+ * Interface to the text service session.
+ * @hide
+ */
+interface ITextServicesSessionListener {
+    oneway void onServiceConnected(in ISpellCheckerSession spellCheckerSession);
+}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 164d581..159b3da 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -50,6 +50,8 @@
     private static final String LOGTAG = "MenuBuilder";
 
     private static final String PRESENTER_KEY = "android:menu:presenters";
+    private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
+    private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview";
 
     private static final int[]  sCategoryToOrder = new int[] {
         1, /* No category */
@@ -308,6 +310,67 @@
         dispatchRestoreInstanceState(state);
     }
 
+    public void saveActionViewStates(Bundle outStates) {
+        SparseArray<Parcelable> viewStates = null;
+
+        final int itemCount = size();
+        for (int i = 0; i < itemCount; i++) {
+            final MenuItem item = getItem(i);
+            final View v = item.getActionView();
+            if (v != null && v.getId() != View.NO_ID) {
+                if (viewStates == null) {
+                    viewStates = new SparseArray<Parcelable>();
+                }
+                v.saveHierarchyState(viewStates);
+                if (item.isActionViewExpanded()) {
+                    outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
+                }
+            }
+            if (item.hasSubMenu()) {
+                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+                subMenu.saveActionViewStates(outStates);
+            }
+        }
+
+        if (viewStates != null) {
+            outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates);
+        }
+    }
+
+    public void restoreActionViewStates(Bundle states) {
+        if (states == null) {
+            return;
+        }
+
+        SparseArray<Parcelable> viewStates = states.getSparseParcelableArray(
+                getActionViewStatesKey());
+
+        final int itemCount = size();
+        for (int i = 0; i < itemCount; i++) {
+            final MenuItem item = getItem(i);
+            final View v = item.getActionView();
+            if (v != null && v.getId() != View.NO_ID) {
+                v.restoreHierarchyState(viewStates);
+            }
+            if (item.hasSubMenu()) {
+                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+                subMenu.restoreActionViewStates(states);
+            }
+        }
+
+        final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID);
+        if (expandedId > 0) {
+            MenuItem itemToExpand = findItem(expandedId);
+            if (itemToExpand != null) {
+                itemToExpand.expandActionView();
+            }
+        }
+    }
+
+    protected String getActionViewStatesKey() {
+        return ACTION_VIEW_STATES_KEY;
+    }
+
     public void setCallback(Callback cb) {
         mCallback = cb;
     }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 541d101..b0a002d 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -553,6 +553,9 @@
     public MenuItem setActionView(View view) {
         mActionView = view;
         mActionProvider = null;
+        if (view != null && view.getId() == View.NO_ID && mId > 0) {
+            view.setId(mId);
+        }
         mMenu.onItemActionRequestChanged(this);
         return this;
     }
diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
index fb1cd5e..92acf8c 100644
--- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
@@ -121,4 +121,13 @@
     public boolean collapseItemActionView(MenuItemImpl item) {
         return mParentMenu.collapseItemActionView(item);
     }
+
+    @Override
+    public String getActionViewStatesKey() {
+        final int itemId = mItem != null ? mItem.getItemId() : 0;
+        if (itemId == 0) {
+            return null;
+        }
+        return super.getActionViewStatesKey() + ":" + itemId;
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index e03858b..8b74f3d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -42,6 +42,7 @@
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.CollapsibleActionView;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -1304,6 +1305,10 @@
             if (mCustomNavView != null) mCustomNavView.setVisibility(GONE);
             requestLayout();
             item.setActionViewExpanded(true);
+
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
+            }
             return true;
         }
 
@@ -1330,11 +1335,16 @@
             if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
                 mCustomNavView.setVisibility(VISIBLE);
             }
+            View collapsedView = mExpandedActionView;
             mExpandedActionView = null;
             mExpandedHomeLayout.setIcon(null);
             mCurrentExpandedItem = null;
             requestLayout();
             item.setActionViewExpanded(false);
+
+            if (collapsedView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) collapsedView).onActionViewCollapsed();
+            }
             return true;
         }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b0c2f2c..b06de9d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -576,18 +576,18 @@
 // ----------------------------------------------------------------------------
 
 static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
-        jobject clazz, DisplayListRenderer* renderer) {
-    return renderer->getDisplayList();
+        jobject clazz, DisplayListRenderer* renderer, DisplayList* displayList) {
+    return renderer->getDisplayList(displayList);
 }
 
-static OpenGLRenderer* android_view_GLES20Canvas_getDisplayListRenderer(JNIEnv* env,
+static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
+        jobject clazz) {
+    return new DisplayListRenderer;
+}
+
+static void android_view_GLES20Canvas_resetDisplayListRenderer(JNIEnv* env,
         jobject clazz, DisplayListRenderer* renderer) {
-    if (renderer == NULL) {
-        renderer = new DisplayListRenderer;
-    } else {
-        renderer->reset();
-    }
-    return renderer;
+    renderer->reset();
 }
 
 static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
@@ -812,9 +812,10 @@
     { "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
             (void*) android_view_GLES20Canvas_getClipBounds },
 
-    { "nGetDisplayList",         "(I)I",       (void*) android_view_GLES20Canvas_getDisplayList },
+    { "nGetDisplayList",         "(II)I",      (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
-    { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
+    { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+    { "nResetDisplayListRenderer", "(I)V",     (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
     { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 103a326..91003d1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1120,6 +1120,13 @@
         android:description="@string/permdesc_bindInputMethod"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a TextService (e.g. SpellCheckerService)
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_TEXT_SERVICE"
+        android:label="@string/permlab_bindTextService"
+        android:description="@string/permdesc_bindTextService"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_WALLPAPER"
@@ -1197,7 +1204,7 @@
     <permission android:name="android.permission.READ_FRAME_BUFFER"
         android:label="@string/permlab_readFrameBuffer"
         android:description="@string/permdesc_readFrameBuffer"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Required to be able to disable the device (very dangerous!). -->
     <permission android:name="android.permission.BRICK"
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index 30518e0..61aa72a 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -19,11 +19,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <scale android:fromXScale="100%p" android:toXScale="100%"
-            android:fromYScale="100%p" android:toYScale="100%"
-            android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:duration="@android:integer/config_mediumAnimTime" />
     <rotate android:fromDegrees="-90" android:toDegrees="0"
             android:pivotX="50%" android:pivotY="50%"
             android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 20943c8..53b0ccd 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -19,11 +19,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <scale android:fromXScale="100%p" android:toXScale="100%"
-            android:fromYScale="100%p" android:toYScale="100%"
-            android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:duration="@android:integer/config_mediumAnimTime" />
     <rotate android:fromDegrees="90" android:toDegrees="0"
             android:pivotX="50%" android:pivotY="50%"
             android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 509ee69..feac38d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -705,6 +705,12 @@
         interface of an input method. Should never be needed for normal applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindTextService">bind to a text service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
+        interface of a text service(e.g. SpellCheckerService). Should never be needed for normal applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindWallpaper">bind to a wallpaper</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
@@ -2675,12 +2681,14 @@
     <!-- USB_STORAGE_ERROR dialog  ok button-->
     <string name="dlg_ok">OK</string>
 
-    <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in MTP mode.  This is the title -->
+    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MTP mode.  This is the title -->
     <string name="usb_mtp_notification_title">Connected as a media device</string>
-    <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in PTP mode.  This is the title -->
+    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode.  This is the title -->
     <string name="usb_ptp_notification_title">Connected as a camera</string>
-    <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in mass storage mode (for installer CD image).  This is the title -->
+    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in mass storage mode (for installer CD image).  This is the title -->
     <string name="usb_cd_installer_notification_title">Connected as an installer</string>
+    <!-- USB_PREFERENCES: Notification for when a USB accessory is attached.  This is the title -->
+    <string name="usb_accessory_notification_title">Connected to a USB accessory</string>
     <!-- See USB_PREFERENCES. This is the message. -->
     <string name="usb_notification_message">Touch for other USB options</string>
 
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index 78d12ef..d32cf66 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -280,7 +280,7 @@
 <td>Run PPP over USB.
 <ul>
 <li><code>&lt;tty&gt;</code> &mdash; the tty for PPP stream. For example <code>dev:/dev/omap_csmi_ttyl</code>. </li>
-<li><code>[parm]... </code> &mdash zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
+<li><code>[parm]... </code> &mdash; zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
 
 <p>Note that you should not automatically start a PPP connection. </p></td>
 <td></td>
diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd
index 5905214..3f94553 100644
--- a/docs/html/guide/topics/intents/intents-filters.jd
+++ b/docs/html/guide/topics/intents/intents-filters.jd
@@ -927,7 +927,7 @@
 
 <p>
 The first, primary, purpose of this activity is to enable the user to 
-interact with a single note &mdash to either {@code VIEW} the note or 
+interact with a single note &mdash; to either {@code VIEW} the note or 
 {@code EDIT} it.  (The {@code EDIT_NOTE} category is a synonym for 
 {@code EDIT}.)  The intent would contain the URI for data matching the 
 MIME type <code>vnd.android.cursor.item/vnd.google.note</code> &mdash;
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index 3486212..743832c 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -710,7 +710,7 @@
 The setting must be one of the values listed in the following table, or a 
 combination of one "{@code state...}" value plus one "{@code adjust...}" 
 value.  Setting multiple values in either group &mdash; multiple 
-"{@code state...}" values, for example &mdash has undefined results.  
+"{@code state...}" values, for example &mdash; has undefined results.  
 Individual values are separated by a vertical bar ({@code |}).  For example:
 </p>
 
@@ -801,4 +801,4 @@
 <dt>see also:</dt>
 <dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> 
 <br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code></dd>
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index 2a84c26..513886a 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -277,7 +277,7 @@
 constants for their columns.  For example, the 
 {@link android.provider.Contacts.Phones android.provider.Contacts.Phones} class 
 defines constants for the names of the columns in the phone table illustrated 
-earlier &mdash {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
+earlier &mdash; {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
 and so on.</li>
 
 <li><p>A filter detailing which rows to return, formatted as an SQL {@code WHERE} 
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 4a85faf..3476bd5 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -504,6 +504,7 @@
     void* ptr = bitmap.getPixels();
     rsAllocationCopyToBitmap(con, (RsAllocation)alloc, ptr, bitmap.getSize());
     bitmap.unlockPixels();
+    bitmap.notifyPixelsChanged();
 }
 
 static void ReleaseBitmapCallback(void *bmp)
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 48d1464..713af92 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -20,6 +20,7 @@
 
 #include <sys/types.h>
 
+#include <media/stagefright/MediaErrors.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/List.h>
@@ -61,6 +62,10 @@
         return 0;
     }
 
+    virtual status_t reconnectAtOffset(off64_t offset) {
+        return ERROR_UNSUPPORTED;
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index 946a0aa..32eed3f 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -99,6 +99,13 @@
     OMX_U32 nUsage;             // OUT
 };
 
+// An enum OMX_COLOR_FormatAndroidOpaque to indicate an opaque colorformat
+// is declared in media/stagefright/openmax/OMX_IVCommon.h
+// This will inform the encoder that the actual
+// colorformat will be relayed by the GRalloc Buffers.
+// OMX_COLOR_FormatAndroidOpaque  = 0x7F000001,
+
+
 }  // namespace android
 
 extern android::OMXPluginBase *createOMXPlugin();
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index 37dbcd8..3818e63 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -29,7 +29,7 @@
 class MediaBuffer;
 class MetaData;
 
-struct MediaSource : public RefBase {
+struct MediaSource : public virtual RefBase {
     MediaSource();
 
     // To be called before any other methods on this object, except
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
new file mode 100644
index 0000000..e1852ec
--- /dev/null
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GUI_SURFACEMEDIASOURCE_H
+#define ANDROID_GUI_SURFACEMEDIASOURCE_H
+
+#include <gui/ISurfaceTexture.h>
+
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaBuffer.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class IGraphicBufferAlloc;
+class String8;
+class GraphicBuffer;
+
+class SurfaceMediaSource : public BnSurfaceTexture, public MediaSource,
+                                            public MediaBufferObserver {
+public:
+    enum { MIN_UNDEQUEUED_BUFFERS = 3 };
+    enum {
+        MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
+        MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
+    };
+    enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
+
+    struct FrameAvailableListener : public virtual RefBase {
+        // onFrameAvailable() is called from queueBuffer() is the FIFO is
+        // empty. You can use SurfaceMediaSource::getQueuedCount() to
+        // figure out if there are more frames waiting.
+        // This is called without any lock held can be called concurrently by
+        // multiple threads.
+        virtual void onFrameAvailable() = 0;
+    };
+
+    SurfaceMediaSource(uint32_t bufW, uint32_t bufH);
+
+    virtual ~SurfaceMediaSource();
+
+
+    // For the MediaSource interface for use by StageFrightRecorder:
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual sp<MetaData> getFormat();
+
+    // Get / Set the frame rate used for encoding. Default fps = 30
+    void setFrameRate(uint32_t fps) ;
+    uint32_t getFrameRate( ) const;
+
+    // The call for the StageFrightRecorder to tell us that
+    // it is done using the MediaBuffer data so that its state
+    // can be set to FREE for dequeuing
+    virtual void signalBufferReturned(MediaBuffer* buffer);
+    // end of MediaSource interface
+
+    uint32_t getBufferCount( ) const { return mBufferCount;}
+
+
+    // setBufferCount updates the number of available buffer slots.  After
+    // calling this all buffer slots are both unallocated and owned by the
+    // SurfaceMediaSource object (i.e. they are not owned by the client).
+    virtual status_t setBufferCount(int bufferCount);
+
+    virtual sp<GraphicBuffer> requestBuffer(int buf);
+
+    // dequeueBuffer gets the next buffer slot index for the client to use. If a
+    // buffer slot is available then that slot index is written to the location
+    // pointed to by the buf argument and a status of OK is returned.  If no
+    // slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
+            uint32_t format, uint32_t usage);
+
+    // queueBuffer returns a filled buffer to the SurfaceMediaSource. In addition, a
+    // timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are client-dependent and should be documented by the
+    // client.
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+    virtual void cancelBuffer(int buf);
+
+    // onFrameReceivedLocked informs the buffer consumers (StageFrightRecorder)
+    // or listeners that a frame has been received
+    // The buffer is not made available for dequeueing immediately. We need to
+    // wait to hear from StageFrightRecorder to set the buffer FREE
+    // Make sure this is called when the mutex is locked
+    virtual status_t onFrameReceivedLocked();
+
+    virtual status_t setScalingMode(int mode) { } // no op for encoding
+    virtual int query(int what, int* value);
+
+    // Just confirming to the ISurfaceTexture interface as of now
+    virtual status_t setCrop(const Rect& reg) { return OK; }
+    virtual status_t setTransform(uint32_t transform) {return OK;}
+
+    // setSynchronousMode set whether dequeueBuffer is synchronous or
+    // asynchronous. In synchronous mode, dequeueBuffer blocks until
+    // a buffer is available, the currently bound buffer can be dequeued and
+    // queued buffers will be retired in order.
+    // The default mode is synchronous.
+    // TODO: Clarify the minute differences bet sycn /async
+    // modes (S.Encoder vis-a-vis SurfaceTexture)
+    virtual status_t setSynchronousMode(bool enabled);
+
+    // connect attempts to connect a client API to the SurfaceMediaSource.  This
+    // must be called before any other ISurfaceTexture methods are called except
+    // for getAllocator.
+    //
+    // This method will fail if the connect was previously called on the
+    // SurfaceMediaSource and no corresponding disconnect call was made.
+    virtual status_t connect(int api);
+
+    // disconnect attempts to disconnect a client API from the SurfaceMediaSource.
+    // Calling this method will cause any subsequent calls to other
+    // ISurfaceTexture methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the SurfaceMediaSource is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api);
+
+    // getqueuedCount returns the number of queued frames waiting in the
+    // FIFO. In asynchronous mode, this always returns 0 or 1 since
+    // frames are not accumulating in the FIFO.
+    size_t getQueuedCount() const;
+
+    // setBufferCountServer set the buffer count. If the client has requested
+    // a buffer count using setBufferCount, the server-buffer count will
+    // take effect once the client sets the count back to zero.
+    status_t setBufferCountServer(int bufferCount);
+
+    // getTimestamp retrieves the timestamp associated with the image
+    // set by the most recent call to updateFrameInfoLocked().
+    //
+    // The timestamp is in nanoseconds, and is monotonically increasing. Its
+    // other semantics (zero point, etc) are source-dependent and should be
+    // documented by the source.
+    int64_t getTimestamp();
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
+
+    // getAllocator retrieves the binder object that must be referenced as long
+    // as the GraphicBuffers dequeued from this SurfaceMediaSource are referenced.
+    // Holding this binder reference prevents SurfaceFlinger from freeing the
+    // buffers before the client is done with them.
+    sp<IBinder> getAllocator();
+
+
+    // getCurrentBuffer returns the buffer associated with the current image.
+    sp<GraphicBuffer> getCurrentBuffer() const;
+
+    // dump our state in a String
+    void dump(String8& result) const;
+    void dump(String8& result, const char* prefix, char* buffer,
+                                                    size_t SIZE) const;
+
+    protected:
+
+    // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
+    // all slots.
+    void freeAllBuffers();
+    static bool isExternalFormat(uint32_t format);
+
+private:
+
+    status_t setBufferCountServerLocked(int bufferCount);
+
+    enum { INVALID_BUFFER_SLOT = -1 };
+
+    struct BufferSlot {
+
+        BufferSlot()
+            : mBufferState(BufferSlot::FREE),
+              mRequestBufferCalled(false),
+              mTimestamp(0) {
+        }
+
+        // mGraphicBuffer points to the buffer allocated for this slot or is
+        // NULL if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // BufferState represents the different states in which a buffer slot
+        // can be.
+        enum BufferState {
+            // FREE indicates that the buffer is not currently being used and
+            // will not be used in the future until it gets dequeued and
+            // subseqently queued by the client.
+            FREE = 0,
+
+            // DEQUEUED indicates that the buffer has been dequeued by the
+            // client, but has not yet been queued or canceled. The buffer is
+            // considered 'owned' by the client, and the server should not use
+            // it for anything.
+            //
+            // Note that when in synchronous-mode (mSynchronousMode == true),
+            // the buffer that's currently attached to the texture may be
+            // dequeued by the client.  That means that the current buffer can
+            // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
+            // however, the current buffer is always in the QUEUED state.
+            DEQUEUED = 1,
+
+            // QUEUED indicates that the buffer has been queued by the client,
+            // and has not since been made available for the client to dequeue.
+            // Attaching the buffer to the texture does NOT transition the
+            // buffer away from the QUEUED state. However, in Synchronous mode
+            // the current buffer may be dequeued by the client under some
+            // circumstances. See the note about the current buffer in the
+            // documentation for DEQUEUED.
+            QUEUED = 2,
+        };
+
+        // mBufferState is the current state of this buffer slot.
+        BufferState mBufferState;
+
+        // mRequestBufferCalled is used for validating that the client did
+        // call requestBuffer() when told to do so. Technically this is not
+        // needed but useful for debugging and catching client bugs.
+        bool mRequestBufferCalled;
+
+        // mTimestamp is the current timestamp for this buffer slot. This gets
+        // to set by queueBuffer each time this slot is queued.
+        int64_t mTimestamp;
+    };
+
+    // mSlots is the array of buffer slots that must be mirrored on the client
+    // side. This allows buffer ownership to be transferred between the client
+    // and server without sending a GraphicBuffer over binder. The entire array
+    // is initialized to NULL at construction time, and buffers are allocated
+    // for a slot when requestBuffer is called with that slot's index.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+    // mDefaultWidth holds the default width of allocated buffers. It is used
+    // in requestBuffers() if a width and height of zero is specified.
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight holds the default height of allocated buffers. It is used
+    // in requestBuffers() if a width and height of zero is specified.
+    uint32_t mDefaultHeight;
+
+    // mPixelFormat holds the pixel format of allocated buffers. It is used
+    // in requestBuffers() if a format of zero is specified.
+    uint32_t mPixelFormat;
+
+    // mBufferCount is the number of buffer slots that the client and server
+    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
+    // by calling setBufferCount or setBufferCountServer
+    int mBufferCount;
+
+    // mClientBufferCount is the number of buffer slots requested by the
+    // client. The default is zero, which means the client doesn't care how
+    // many buffers there are
+    int mClientBufferCount;
+
+    // mServerBufferCount buffer count requested by the server-side
+    int mServerBufferCount;
+
+    // mCurrentSlot is the buffer slot index of the buffer that is currently
+    // being used by buffer consumer
+    // (e.g. StageFrightRecorder in the case of SurfaceMediaSource or GLTexture
+    // in the case of SurfaceTexture).
+    // It is initialized to INVALID_BUFFER_SLOT,
+    // indicating that no buffer slot is currently bound to the texture. Note,
+    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+    // that no buffer is bound to the texture. A call to setBufferCount will
+    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
+    int mCurrentSlot;
+
+
+    // mCurrentBuf is the graphic buffer of the current slot to be used by
+    // buffer consumer. It's possible that this buffer is not associated
+    // with any buffer slot, so we must track it separately in order to
+    // properly use IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
+    sp<GraphicBuffer> mCurrentBuf;
+
+
+    // mCurrentTimestamp is the timestamp for the current texture. It
+    // gets set to mLastQueuedTimestamp each time updateTexImage is called.
+    int64_t mCurrentTimestamp;
+
+    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
+    // allocate new GraphicBuffer objects.
+    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
+
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    sp<FrameAvailableListener> mFrameAvailableListener;
+
+    // mSynchronousMode whether we're in synchronous mode or not
+    bool mSynchronousMode;
+
+    // mConnectedApi indicates the API that is currently connected to this
+    // SurfaceTexture.  It defaults to NO_CONNECTED_API (= 0), and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
+    mutable Condition mDequeueCondition;
+
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode
+    typedef Vector<int> Fifo;
+    Fifo mQueue;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of SurfaceMediaSource objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    ////////////////////////// For MediaSource
+    // Set to a default of 30 fps if not specified by the client side
+    int32_t mFrameRate;
+
+    // mStarted is a flag to check if the recording has started
+    bool mStarted;
+
+    // mFrameAvailableCondition condition used to indicate whether there
+    // is a frame available for dequeuing
+    Condition mFrameAvailableCondition;
+    Condition mFrameCompleteCondition;
+
+    // Avoid copying and equating and default constructor
+    DISALLOW_IMPLICIT_CONSTRUCTORS(SurfaceMediaSource);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SURFACEMEDIASOURCE_H
diff --git a/include/media/stagefright/openmax/OMX_IVCommon.h b/include/media/stagefright/openmax/OMX_IVCommon.h
index 7ed072b..97170d7 100644
--- a/include/media/stagefright/openmax/OMX_IVCommon.h
+++ b/include/media/stagefright/openmax/OMX_IVCommon.h
@@ -16,29 +16,29 @@
  * -------------------------------------------------------------------
  */
 /**
- * Copyright (c) 2008 The Khronos Group Inc. 
- * 
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
  * "Software"), to deal in the Software without restriction, including
  * without limitation the rights to use, copy, modify, merge, publish,
  * distribute, sublicense, and/or sell copies of the Software, and to
  * permit persons to whom the Software is furnished to do so, subject
- * to the following conditions: 
+ * to the following conditions:
  * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software. 
- * 
+ * in all copies or substantial portions of the Software.
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  */
 
-/** 
+/**
  * @file OMX_IVCommon.h - OpenMax IL version 1.1.2
  *  The structures needed by Video and Image components to exchange
  *  parameters and configuration data with the components.
@@ -53,7 +53,7 @@
 /**
  * Each OMX header must include all required header files to allow the header
  * to compile without errors.  The includes below are required for this header
- * file to compile successfully 
+ * file to compile successfully
  */
 
 #include <OMX_Core.h>
@@ -64,8 +64,8 @@
  */
 
 
-/** 
- * Enumeration defining possible uncompressed image/video formats. 
+/**
+ * Enumeration defining possible uncompressed image/video formats.
  *
  * ENUMS:
  *  Unused                 : Placeholder value when format is N/A
@@ -113,7 +113,7 @@
     OMX_COLOR_Format16bitBGR565,
     OMX_COLOR_Format18bitRGB666,
     OMX_COLOR_Format18bitARGB1665,
-    OMX_COLOR_Format19bitARGB1666, 
+    OMX_COLOR_Format19bitARGB1666,
     OMX_COLOR_Format24bitRGB888,
     OMX_COLOR_Format24bitBGR888,
     OMX_COLOR_Format24bitARGB1887,
@@ -136,55 +136,62 @@
     OMX_COLOR_FormatRawBayer8bit,
     OMX_COLOR_FormatRawBayer10bit,
     OMX_COLOR_FormatRawBayer8bitcompressed,
-    OMX_COLOR_FormatL2, 
-    OMX_COLOR_FormatL4, 
-    OMX_COLOR_FormatL8, 
-    OMX_COLOR_FormatL16, 
-    OMX_COLOR_FormatL24, 
+    OMX_COLOR_FormatL2,
+    OMX_COLOR_FormatL4,
+    OMX_COLOR_FormatL8,
+    OMX_COLOR_FormatL16,
+    OMX_COLOR_FormatL24,
     OMX_COLOR_FormatL32,
     OMX_COLOR_FormatYUV420PackedSemiPlanar,
     OMX_COLOR_FormatYUV422PackedSemiPlanar,
     OMX_COLOR_Format18BitBGR666,
     OMX_COLOR_Format24BitARGB6666,
     OMX_COLOR_Format24BitABGR6666,
-    OMX_COLOR_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_COLOR_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_COLOR_FormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    /**<Reserved android opaque colorformat. Tells the encoder that
+     * the actual colorformat will be  relayed by the
+     * Gralloc Buffers.
+     * FIXME: In the process of reserving some enum values for
+     * Android-specific OMX IL colorformats. Change this enum to
+     * an acceptable range once that is done.*/
+    OMX_COLOR_FormatAndroidOpaque = 0x7F000001,
     OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100,
     OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00,
     OMX_COLOR_FormatMax = 0x7FFFFFFF
 } OMX_COLOR_FORMATTYPE;
 
 
-/** 
+/**
  * Defines the matrix for conversion from RGB to YUV or vice versa.
- * iColorMatrix should be initialized with the fixed point values 
+ * iColorMatrix should be initialized with the fixed point values
  * used in converting between formats.
  */
 typedef struct OMX_CONFIG_COLORCONVERSIONTYPE {
     OMX_U32 nSize;              /**< Size of the structure in bytes */
-    OMX_VERSIONTYPE nVersion;   /**< OMX specification version info */ 
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version info */
     OMX_U32 nPortIndex;         /**< Port that this struct applies to */
     OMX_S32 xColorMatrix[3][3]; /**< Stored in signed Q16 format */
     OMX_S32 xColorOffset[4];    /**< Stored in signed Q16 format */
 }OMX_CONFIG_COLORCONVERSIONTYPE;
 
 
-/** 
- * Structure defining percent to scale each frame dimension.  For example:  
+/**
+ * Structure defining percent to scale each frame dimension.  For example:
  * To make the width 50% larger, use fWidth = 1.5 and to make the width
  * 1/2 the original size, use fWidth = 0.5
  */
 typedef struct OMX_CONFIG_SCALEFACTORTYPE {
     OMX_U32 nSize;            /**< Size of the structure in bytes */
-    OMX_VERSIONTYPE nVersion; /**< OMX specification version info */ 
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version info */
     OMX_U32 nPortIndex;       /**< Port that this struct applies to */
     OMX_S32 xWidth;           /**< Fixed point value stored as Q16 */
     OMX_S32 xHeight;          /**< Fixed point value stored as Q16 */
 }OMX_CONFIG_SCALEFACTORTYPE;
 
 
-/** 
- * Enumeration of possible image filter types 
+/**
+ * Enumeration of possible image filter types
  */
 typedef enum OMX_IMAGEFILTERTYPE {
     OMX_ImageFilterNone,
@@ -195,23 +202,23 @@
     OMX_ImageFilterOilPaint,
     OMX_ImageFilterHatch,
     OMX_ImageFilterGpen,
-    OMX_ImageFilterAntialias, 
-    OMX_ImageFilterDeRing,       
+    OMX_ImageFilterAntialias,
+    OMX_ImageFilterDeRing,
     OMX_ImageFilterSolarize,
-    OMX_ImageFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_ImageFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_ImageFilterVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_ImageFilterMax = 0x7FFFFFFF
 } OMX_IMAGEFILTERTYPE;
 
 
-/** 
- * Image filter configuration 
+/**
+ * Image filter configuration
  *
  * STRUCT MEMBERS:
- *  nSize        : Size of the structure in bytes       
+ *  nSize        : Size of the structure in bytes
  *  nVersion     : OMX specification version information
- *  nPortIndex   : Port that this structure applies to 
- *  eImageFilter : Image filter type enumeration      
+ *  nPortIndex   : Port that this structure applies to
+ *  eImageFilter : Image filter type enumeration
  */
 typedef struct OMX_CONFIG_IMAGEFILTERTYPE {
     OMX_U32 nSize;
@@ -221,22 +228,22 @@
 } OMX_CONFIG_IMAGEFILTERTYPE;
 
 
-/** 
- * Customized U and V for color enhancement 
+/**
+ * Customized U and V for color enhancement
  *
  * STRUCT MEMBERS:
  *  nSize             : Size of the structure in bytes
- *  nVersion          : OMX specification version information 
+ *  nVersion          : OMX specification version information
  *  nPortIndex        : Port that this structure applies to
  *  bColorEnhancement : Enable/disable color enhancement
- *  nCustomizedU      : Practical values: 16-240, range: 0-255, value set for 
+ *  nCustomizedU      : Practical values: 16-240, range: 0-255, value set for
  *                      U component
- *  nCustomizedV      : Practical values: 16-240, range: 0-255, value set for 
+ *  nCustomizedV      : Practical values: 16-240, range: 0-255, value set for
  *                      V component
  */
 typedef struct OMX_CONFIG_COLORENHANCEMENTTYPE {
     OMX_U32 nSize;
-    OMX_VERSIONTYPE nVersion; 
+    OMX_VERSIONTYPE nVersion;
     OMX_U32 nPortIndex;
     OMX_BOOL bColorEnhancement;
     OMX_U8 nCustomizedU;
@@ -244,12 +251,12 @@
 } OMX_CONFIG_COLORENHANCEMENTTYPE;
 
 
-/** 
- * Define color key and color key mask 
+/**
+ * Define color key and color key mask
  *
  * STRUCT MEMBERS:
  *  nSize      : Size of the structure in bytes
- *  nVersion   : OMX specification version information 
+ *  nVersion   : OMX specification version information
  *  nPortIndex : Port that this structure applies to
  *  nARGBColor : 32bit Alpha, Red, Green, Blue Color
  *  nARGBMask  : 32bit Mask for Alpha, Red, Green, Blue channels
@@ -263,12 +270,12 @@
 } OMX_CONFIG_COLORKEYTYPE;
 
 
-/** 
- * List of color blend types for pre/post processing 
+/**
+ * List of color blend types for pre/post processing
  *
  * ENUMS:
  *  None          : No color blending present
- *  AlphaConstant : Function is (alpha_constant * src) + 
+ *  AlphaConstant : Function is (alpha_constant * src) +
  *                  (1 - alpha_constant) * dst)
  *  AlphaPerPixel : Function is (alpha * src) + (1 - alpha) * dst)
  *  Alternate     : Function is alternating pixels from src and dst
@@ -284,21 +291,21 @@
     OMX_ColorBlendAnd,
     OMX_ColorBlendOr,
     OMX_ColorBlendInvert,
-    OMX_ColorBlendKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_ColorBlendKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_ColorBlendVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_ColorBlendMax = 0x7FFFFFFF
 } OMX_COLORBLENDTYPE;
 
 
-/** 
- * Color blend configuration 
+/**
+ * Color blend configuration
  *
  * STRUCT MEMBERS:
- *  nSize             : Size of the structure in bytes                        
- *  nVersion          : OMX specification version information                
- *  nPortIndex        : Port that this structure applies to                   
+ *  nSize             : Size of the structure in bytes
+ *  nVersion          : OMX specification version information
+ *  nPortIndex        : Port that this structure applies to
  *  nRGBAlphaConstant : Constant global alpha values when global alpha is used
- *  eColorBlend       : Color blend type enumeration                         
+ *  eColorBlend       : Color blend type enumeration
  */
 typedef struct OMX_CONFIG_COLORBLENDTYPE {
     OMX_U32 nSize;
@@ -309,15 +316,15 @@
 } OMX_CONFIG_COLORBLENDTYPE;
 
 
-/** 
+/**
  * Hold frame dimension
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes      
+ *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
- *  nPortIndex : Port that this structure applies to     
- *  nWidth     : Frame width in pixels                 
- *  nHeight    : Frame height in pixels                
+ *  nPortIndex : Port that this structure applies to
+ *  nWidth     : Frame width in pixels
+ *  nHeight    : Frame height in pixels
  */
 typedef struct OMX_FRAMESIZETYPE {
     OMX_U32 nSize;
@@ -329,69 +336,69 @@
 
 
 /**
- * Rotation configuration 
+ * Rotation configuration
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes             
+ *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
  *  nPortIndex : Port that this structure applies to
- *  nRotation  : +/- integer rotation value               
+ *  nRotation  : +/- integer rotation value
  */
 typedef struct OMX_CONFIG_ROTATIONTYPE {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
     OMX_U32 nPortIndex;
-    OMX_S32 nRotation; 
+    OMX_S32 nRotation;
 } OMX_CONFIG_ROTATIONTYPE;
 
 
-/** 
- * Possible mirroring directions for pre/post processing 
+/**
+ * Possible mirroring directions for pre/post processing
  *
  * ENUMS:
- *  None       : No mirroring                         
- *  Vertical   : Vertical mirroring, flip on X axis   
- *  Horizontal : Horizontal mirroring, flip on Y axis  
+ *  None       : No mirroring
+ *  Vertical   : Vertical mirroring, flip on X axis
+ *  Horizontal : Horizontal mirroring, flip on Y axis
  *  Both       : Both vertical and horizontal mirroring
  */
 typedef enum OMX_MIRRORTYPE {
     OMX_MirrorNone = 0,
     OMX_MirrorVertical,
     OMX_MirrorHorizontal,
-    OMX_MirrorBoth, 
-    OMX_MirrorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_MirrorBoth,
+    OMX_MirrorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_MirrorVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
-    OMX_MirrorMax = 0x7FFFFFFF   
+    OMX_MirrorMax = 0x7FFFFFFF
 } OMX_MIRRORTYPE;
 
 
-/** 
- * Mirroring configuration 
+/**
+ * Mirroring configuration
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes      
+ *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
- *  nPortIndex : Port that this structure applies to  
- *  eMirror    : Mirror type enumeration              
+ *  nPortIndex : Port that this structure applies to
+ *  eMirror    : Mirror type enumeration
  */
 typedef struct OMX_CONFIG_MIRRORTYPE {
     OMX_U32 nSize;
-    OMX_VERSIONTYPE nVersion; 
+    OMX_VERSIONTYPE nVersion;
     OMX_U32 nPortIndex;
     OMX_MIRRORTYPE  eMirror;
 } OMX_CONFIG_MIRRORTYPE;
 
 
-/** 
- * Position information only 
+/**
+ * Position information only
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes               
+ *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
  *  nPortIndex : Port that this structure applies to
- *  nX         : X coordinate for the point                     
- *  nY         : Y coordinate for the point 
- */                      
+ *  nX         : X coordinate for the point
+ *  nY         : Y coordinate for the point
+ */
 typedef struct OMX_CONFIG_POINTTYPE {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
@@ -401,37 +408,37 @@
 } OMX_CONFIG_POINTTYPE;
 
 
-/** 
- * Frame size plus position 
+/**
+ * Frame size plus position
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes                    
- *  nVersion   : OMX specification version information      
- *  nPortIndex : Port that this structure applies to    
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
  *  nLeft      : X Coordinate of the top left corner of the rectangle
  *  nTop       : Y Coordinate of the top left corner of the rectangle
- *  nWidth     : Width of the rectangle                              
- *  nHeight    : Height of the rectangle                             
+ *  nWidth     : Width of the rectangle
+ *  nHeight    : Height of the rectangle
  */
 typedef struct OMX_CONFIG_RECTTYPE {
     OMX_U32 nSize;
-    OMX_VERSIONTYPE nVersion;  
-    OMX_U32 nPortIndex; 
-    OMX_S32 nLeft; 
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nLeft;
     OMX_S32 nTop;
     OMX_U32 nWidth;
     OMX_U32 nHeight;
 } OMX_CONFIG_RECTTYPE;
 
 
-/** 
- * Deblocking state; it is required to be set up before starting the codec 
+/**
+ * Deblocking state; it is required to be set up before starting the codec
  *
  * STRUCT MEMBERS:
- *  nSize       : Size of the structure in bytes      
- *  nVersion    : OMX specification version information 
+ *  nSize       : Size of the structure in bytes
+ *  nVersion    : OMX specification version information
  *  nPortIndex  : Port that this structure applies to
- *  bDeblocking : Enable/disable deblocking mode    
+ *  bDeblocking : Enable/disable deblocking mode
  */
 typedef struct OMX_PARAM_DEBLOCKINGTYPE {
     OMX_U32 nSize;
@@ -441,13 +448,13 @@
 } OMX_PARAM_DEBLOCKINGTYPE;
 
 
-/** 
- * Stabilization state 
+/**
+ * Stabilization state
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes          
- *  nVersion   : OMX specification version information    
- *  nPortIndex : Port that this structure applies to   
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
  *  bStab      : Enable/disable frame stabilization state
  */
 typedef struct OMX_CONFIG_FRAMESTABTYPE {
@@ -458,8 +465,8 @@
 } OMX_CONFIG_FRAMESTABTYPE;
 
 
-/** 
- * White Balance control type 
+/**
+ * White Balance control type
  *
  * STRUCT MEMBERS:
  *  SunLight : Referenced in JSR-234
@@ -476,20 +483,20 @@
     OMX_WhiteBalControlIncandescent,
     OMX_WhiteBalControlFlash,
     OMX_WhiteBalControlHorizon,
-    OMX_WhiteBalControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_WhiteBalControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_WhiteBalControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_WhiteBalControlMax = 0x7FFFFFFF
 } OMX_WHITEBALCONTROLTYPE;
 
 
-/** 
- * White Balance control configuration 
+/**
+ * White Balance control configuration
  *
  * STRUCT MEMBERS:
- *  nSize            : Size of the structure in bytes       
+ *  nSize            : Size of the structure in bytes
  *  nVersion         : OMX specification version information
- *  nPortIndex       : Port that this structure applies to                 
- *  eWhiteBalControl : White balance enumeration            
+ *  nPortIndex       : Port that this structure applies to
+ *  eWhiteBalControl : White balance enumeration
  */
 typedef struct OMX_CONFIG_WHITEBALCONTROLTYPE {
     OMX_U32 nSize;
@@ -499,8 +506,8 @@
 } OMX_CONFIG_WHITEBALCONTROLTYPE;
 
 
-/** 
- * Exposure control type 
+/**
+ * Exposure control type
  */
 typedef enum OMX_EXPOSURECONTROLTYPE {
     OMX_ExposureControlOff = 0,
@@ -513,20 +520,20 @@
     OMX_ExposureControlBeach,
     OMX_ExposureControlLargeAperture,
     OMX_ExposureControlSmallApperture,
-    OMX_ExposureControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_ExposureControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_ExposureControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_ExposureControlMax = 0x7FFFFFFF
 } OMX_EXPOSURECONTROLTYPE;
 
 
-/** 
- * White Balance control configuration 
+/**
+ * White Balance control configuration
  *
  * STRUCT MEMBERS:
- *  nSize            : Size of the structure in bytes      
+ *  nSize            : Size of the structure in bytes
  *  nVersion         : OMX specification version information
- *  nPortIndex       : Port that this structure applies to                
- *  eExposureControl : Exposure control enumeration         
+ *  nPortIndex       : Port that this structure applies to
+ *  eExposureControl : Exposure control enumeration
  */
 typedef struct OMX_CONFIG_EXPOSURECONTROLTYPE {
     OMX_U32 nSize;
@@ -536,16 +543,16 @@
 } OMX_CONFIG_EXPOSURECONTROLTYPE;
 
 
-/** 
- * Defines sensor supported mode. 
+/**
+ * Defines sensor supported mode.
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes           
+ *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
- *  nPortIndex : Port that this structure applies to 
- *  nFrameRate : Single shot mode is indicated by a 0     
+ *  nPortIndex : Port that this structure applies to
+ *  nFrameRate : Single shot mode is indicated by a 0
  *  bOneShot   : Enable for single shot, disable for streaming
- *  sFrameSize : Framesize                                          
+ *  sFrameSize : Framesize
  */
 typedef struct OMX_PARAM_SENSORMODETYPE {
     OMX_U32 nSize;
@@ -557,13 +564,13 @@
 } OMX_PARAM_SENSORMODETYPE;
 
 
-/** 
- * Defines contrast level 
+/**
+ * Defines contrast level
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes                              
- *  nVersion   : OMX specification version information                
- *  nPortIndex : Port that this structure applies to                 
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
  *  nContrast  : Values allowed for contrast -100 to 100, zero means no change
  */
 typedef struct OMX_CONFIG_CONTRASTTYPE {
@@ -574,14 +581,14 @@
 } OMX_CONFIG_CONTRASTTYPE;
 
 
-/** 
- * Defines brightness level 
+/**
+ * Defines brightness level
  *
  * STRUCT MEMBERS:
- *  nSize       : Size of the structure in bytes          
- *  nVersion    : OMX specification version information 
- *  nPortIndex  : Port that this structure applies to 
- *  nBrightness : 0-100%        
+ *  nSize       : Size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  nPortIndex  : Port that this structure applies to
+ *  nBrightness : 0-100%
  */
 typedef struct OMX_CONFIG_BRIGHTNESSTYPE {
     OMX_U32 nSize;
@@ -591,16 +598,16 @@
 } OMX_CONFIG_BRIGHTNESSTYPE;
 
 
-/** 
- * Defines backlight level configuration for a video sink, e.g. LCD panel 
+/**
+ * Defines backlight level configuration for a video sink, e.g. LCD panel
  *
  * STRUCT MEMBERS:
  *  nSize      : Size of the structure in bytes
- *  nVersion   : OMX specification version information 
+ *  nVersion   : OMX specification version information
  *  nPortIndex : Port that this structure applies to
  *  nBacklight : Values allowed for backlight 0-100%
- *  nTimeout   : Number of milliseconds before backlight automatically turns 
- *               off.  A value of 0x0 disables backight timeout 
+ *  nTimeout   : Number of milliseconds before backlight automatically turns
+ *               off.  A value of 0x0 disables backight timeout
  */
 typedef struct OMX_CONFIG_BACKLIGHTTYPE {
     OMX_U32 nSize;
@@ -611,12 +618,12 @@
 } OMX_CONFIG_BACKLIGHTTYPE;
 
 
-/** 
- * Defines setting for Gamma 
+/**
+ * Defines setting for Gamma
  *
  * STRUCT MEMBERS:
  *  nSize      : Size of the structure in bytes
- *  nVersion   : OMX specification version information 
+ *  nVersion   : OMX specification version information
  *  nPortIndex : Port that this structure applies to
  *  nGamma     : Values allowed for gamma -100 to 100, zero means no change
  */
@@ -628,14 +635,14 @@
 } OMX_CONFIG_GAMMATYPE;
 
 
-/** 
- * Define for setting saturation 
- * 
+/**
+ * Define for setting saturation
+ *
  * STRUCT MEMBERS:
  *  nSize       : Size of the structure in bytes
  *  nVersion    : OMX specification version information
  *  nPortIndex  : Port that this structure applies to
- *  nSaturation : Values allowed for saturation -100 to 100, zero means 
+ *  nSaturation : Values allowed for saturation -100 to 100, zero means
  *                no change
  */
 typedef struct OMX_CONFIG_SATURATIONTYPE {
@@ -646,14 +653,14 @@
 } OMX_CONFIG_SATURATIONTYPE;
 
 
-/** 
- * Define for setting Lightness 
+/**
+ * Define for setting Lightness
  *
  * STRUCT MEMBERS:
  *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
  *  nPortIndex : Port that this structure applies to
- *  nLightness : Values allowed for lightness -100 to 100, zero means no 
+ *  nLightness : Values allowed for lightness -100 to 100, zero means no
  *               change
  */
 typedef struct OMX_CONFIG_LIGHTNESSTYPE {
@@ -664,17 +671,17 @@
 } OMX_CONFIG_LIGHTNESSTYPE;
 
 
-/** 
- * Plane blend configuration 
+/**
+ * Plane blend configuration
  *
  * STRUCT MEMBERS:
- *  nSize      : Size of the structure in bytes 
+ *  nSize      : Size of the structure in bytes
  *  nVersion   : OMX specification version information
  *  nPortIndex : Index of input port associated with the plane.
- *  nDepth     : Depth of the plane in relation to the screen. Higher 
- *               numbered depths are "behind" lower number depths.  
+ *  nDepth     : Depth of the plane in relation to the screen. Higher
+ *               numbered depths are "behind" lower number depths.
  *               This number defaults to the Port Index number.
- *  nAlpha     : Transparency blending component for the entire plane.  
+ *  nAlpha     : Transparency blending component for the entire plane.
  *               See blending modes for more detail.
  */
 typedef struct OMX_CONFIG_PLANEBLENDTYPE {
@@ -686,17 +693,17 @@
 } OMX_CONFIG_PLANEBLENDTYPE;
 
 
-/** 
+/**
  * Define interlace type
  *
  * STRUCT MEMBERS:
- *  nSize                 : Size of the structure in bytes 
- *  nVersion              : OMX specification version information 
+ *  nSize                 : Size of the structure in bytes
+ *  nVersion              : OMX specification version information
  *  nPortIndex            : Port that this structure applies to
- *  bEnable               : Enable control variable for this functionality 
+ *  bEnable               : Enable control variable for this functionality
  *                          (see below)
- *  nInterleavePortIndex  : Index of input or output port associated with  
- *                          the interleaved plane. 
+ *  nInterleavePortIndex  : Index of input or output port associated with
+ *                          the interleaved plane.
  *  pPlanarPortIndexes[4] : Index of input or output planar ports.
  */
 typedef struct OMX_PARAM_INTERLEAVETYPE {
@@ -708,8 +715,8 @@
 } OMX_PARAM_INTERLEAVETYPE;
 
 
-/** 
- * Defines the picture effect used for an input picture 
+/**
+ * Defines the picture effect used for an input picture
  */
 typedef enum OMX_TRANSITIONEFFECTTYPE {
     OMX_EffectNone,
@@ -719,18 +726,18 @@
     OMX_EffectDissolve,
     OMX_EffectWipe,
     OMX_EffectUnspecifiedMixOfTwoScenes,
-    OMX_EffectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_EffectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_EffectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_EffectMax = 0x7FFFFFFF
 } OMX_TRANSITIONEFFECTTYPE;
 
 
-/** 
- * Structure used to configure current transition effect 
+/**
+ * Structure used to configure current transition effect
  *
  * STRUCT MEMBERS:
  * nSize      : Size of the structure in bytes
- * nVersion   : OMX specification version information 
+ * nVersion   : OMX specification version information
  * nPortIndex : Port that this structure applies to
  * eEffect    : Effect to enable
  */
@@ -742,43 +749,43 @@
 } OMX_CONFIG_TRANSITIONEFFECTTYPE;
 
 
-/** 
- * Defines possible data unit types for encoded video data. The data unit 
+/**
+ * Defines possible data unit types for encoded video data. The data unit
  * types are used both for encoded video input for playback as well as
- * encoded video output from recording. 
+ * encoded video output from recording.
  */
 typedef enum OMX_DATAUNITTYPE {
     OMX_DataUnitCodedPicture,
     OMX_DataUnitVideoSegment,
     OMX_DataUnitSeveralSegments,
     OMX_DataUnitArbitraryStreamSection,
-    OMX_DataUnitKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_DataUnitKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_DataUnitVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_DataUnitMax = 0x7FFFFFFF
 } OMX_DATAUNITTYPE;
 
 
-/** 
- * Defines possible encapsulation types for coded video data unit. The 
- * encapsulation information is used both for encoded video input for 
- * playback as well as encoded video output from recording. 
+/**
+ * Defines possible encapsulation types for coded video data unit. The
+ * encapsulation information is used both for encoded video input for
+ * playback as well as encoded video output from recording.
  */
 typedef enum OMX_DATAUNITENCAPSULATIONTYPE {
     OMX_DataEncapsulationElementaryStream,
     OMX_DataEncapsulationGenericPayload,
     OMX_DataEncapsulationRtpPayload,
-    OMX_DataEncapsulationKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_DataEncapsulationKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_DataEncapsulationVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_DataEncapsulationMax = 0x7FFFFFFF
 } OMX_DATAUNITENCAPSULATIONTYPE;
 
 
-/** 
- * Structure used to configure the type of being decoded/encoded 
+/**
+ * Structure used to configure the type of being decoded/encoded
  */
 typedef struct OMX_PARAM_DATAUNITTYPE {
     OMX_U32 nSize;            /**< Size of the structure in bytes */
-    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ 
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
     OMX_U32 nPortIndex;       /**< Port that this structure applies to */
     OMX_DATAUNITTYPE eUnitType;
     OMX_DATAUNITENCAPSULATIONTYPE eEncapsulationType;
@@ -786,25 +793,25 @@
 
 
 /**
- * Defines dither types 
+ * Defines dither types
  */
 typedef enum OMX_DITHERTYPE {
     OMX_DitherNone,
     OMX_DitherOrdered,
     OMX_DitherErrorDiffusion,
     OMX_DitherOther,
-    OMX_DitherKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_DitherKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_DitherVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_DitherMax = 0x7FFFFFFF
 } OMX_DITHERTYPE;
 
 
-/** 
- * Structure used to configure current type of dithering 
+/**
+ * Structure used to configure current type of dithering
  */
 typedef struct OMX_CONFIG_DITHERTYPE {
     OMX_U32 nSize;            /**< Size of the structure in bytes */
-    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ 
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
     OMX_U32 nPortIndex;       /**< Port that this structure applies to */
     OMX_DITHERTYPE eDither;   /**< Type of dithering to use */
 } OMX_CONFIG_DITHERTYPE;
@@ -813,28 +820,28 @@
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
     OMX_U32 nPortIndex;     /**< Port that this structure applies to */
-    OMX_BOOL bContinuous;   /**< If true then ignore frame rate and emit capture 
+    OMX_BOOL bContinuous;   /**< If true then ignore frame rate and emit capture
                              *   data as fast as possible (otherwise obey port's frame rate). */
-    OMX_BOOL bFrameLimited; /**< If true then terminate capture after the port emits the 
-                             *   specified number of frames (otherwise the port does not 
-                             *   terminate the capture until instructed to do so by the client). 
-                             *   Even if set, the client may manually terminate the capture prior 
+    OMX_BOOL bFrameLimited; /**< If true then terminate capture after the port emits the
+                             *   specified number of frames (otherwise the port does not
+                             *   terminate the capture until instructed to do so by the client).
+                             *   Even if set, the client may manually terminate the capture prior
                              *   to reaching the limit. */
     OMX_U32 nFrameLimit;      /**< Limit on number of frames emitted during a capture (only
                                *   valid if bFrameLimited is set). */
 } OMX_CONFIG_CAPTUREMODETYPE;
 
 typedef enum OMX_METERINGTYPE {
- 
+
     OMX_MeteringModeAverage,     /**< Center-weighted average metering. */
     OMX_MeteringModeSpot,  	      /**< Spot (partial) metering. */
     OMX_MeteringModeMatrix,      /**< Matrix or evaluative metering. */
- 
-    OMX_MeteringKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+
+    OMX_MeteringKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_MeteringVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_EVModeMax = 0x7fffffff
 } OMX_METERINGTYPE;
- 
+
 typedef struct OMX_CONFIG_EXPOSUREVALUETYPE {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
@@ -843,14 +850,14 @@
     OMX_S32 xEVCompensation;      /**< Fixed point value stored as Q16 */
     OMX_U32 nApertureFNumber;     /**< e.g. nApertureFNumber = 2 implies "f/2" - Q16 format */
     OMX_BOOL bAutoAperture;		/**< Whether aperture number is defined automatically */
-    OMX_U32 nShutterSpeedMsec;    /**< Shutterspeed in milliseconds */ 
-    OMX_BOOL bAutoShutterSpeed;	/**< Whether shutter speed is defined automatically */ 
+    OMX_U32 nShutterSpeedMsec;    /**< Shutterspeed in milliseconds */
+    OMX_BOOL bAutoShutterSpeed;	/**< Whether shutter speed is defined automatically */
     OMX_U32 nSensitivity;         /**< e.g. nSensitivity = 100 implies "ISO 100" */
     OMX_BOOL bAutoSensitivity;	/**< Whether sensitivity is defined automatically */
 } OMX_CONFIG_EXPOSUREVALUETYPE;
 
-/** 
- * Focus region configuration 
+/**
+ * Focus region configuration
  *
  * STRUCT MEMBERS:
  *  nSize           : Size of the structure in bytes
@@ -881,8 +888,8 @@
     OMX_BOOL bBottomRight;
 } OMX_CONFIG_FOCUSREGIONTYPE;
 
-/** 
- * Focus Status type 
+/**
+ * Focus Status type
  */
 typedef enum OMX_FOCUSSTATUSTYPE {
     OMX_FocusStatusOff = 0,
@@ -890,13 +897,13 @@
     OMX_FocusStatusReached,
     OMX_FocusStatusUnableToReach,
     OMX_FocusStatusLost,
-    OMX_FocusStatusKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_FocusStatusKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_FocusStatusVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_FocusStatusMax = 0x7FFFFFFF
 } OMX_FOCUSSTATUSTYPE;
 
-/** 
- * Focus status configuration 
+/**
+ * Focus status configuration
  *
  * STRUCT MEMBERS:
  *  nSize               : Size of the structure in bytes
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index f46f25c..848c5a1 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -55,7 +55,7 @@
 
     PIXEL_FORMAT_OPAQUE         = -1,
         // System chooses an opaque format (no alpha bits required)
-    
+
     // real pixel formats supported for rendering -----------------------------
 
     PIXEL_FORMAT_RGBA_8888   = HAL_PIXEL_FORMAT_RGBA_8888,  // 4x8-bit RGBA
@@ -84,7 +84,7 @@
         INDEX_GREEN   = 2,
         INDEX_BLUE    = 3
     };
-    
+
     enum { // components
         ALPHA               = 1,
         RGB                 = 2,
@@ -98,10 +98,10 @@
         uint8_t h;
         uint8_t l;
     };
-    
+
     inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
     size_t getScanlineSize(unsigned int width) const;
-    size_t getSize(size_t ci) const { 
+    size_t getSize(size_t ci) const {
         return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
     }
     size_t      version;
@@ -112,7 +112,7 @@
         szinfo      cinfo[4];
         struct {
             uint8_t     h_alpha;
-            uint8_t     l_alpha;    
+            uint8_t     l_alpha;
             uint8_t     h_red;
             uint8_t     l_red;
             uint8_t     h_green;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index b4d76bb..688b99b 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -55,6 +55,9 @@
     mQueryWidth = 0;
     mQueryHeight = 0;
     mQueryFormat = 0;
+    mDefaultWidth = 0;
+    mDefaultHeight = 0;
+    mTransformHint = 0;
     mConnectedToCpu = false;
 }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 8b1caeee..886c05c 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -883,7 +883,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE) {
-    mDisplayList = NULL;
 }
 
 DisplayListRenderer::~DisplayListRenderer() {
@@ -923,13 +922,13 @@
 // Operations
 ///////////////////////////////////////////////////////////////////////////////
 
-DisplayList* DisplayListRenderer::getDisplayList() {
-    if (mDisplayList == NULL) {
-        mDisplayList = new DisplayList(*this);
+DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) {
+    if (!displayList) {
+        displayList = new DisplayList(*this);
     } else {
-        mDisplayList->initFromDisplayListRenderer(*this, true);
+        displayList->initFromDisplayListRenderer(*this, true);
     }
-    return mDisplayList;
+    return displayList;
 }
 
 void DisplayListRenderer::setViewport(int width, int height) {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b83259f..8157631 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -217,7 +217,7 @@
     DisplayListRenderer();
     ~DisplayListRenderer();
 
-    DisplayList* getDisplayList();
+    DisplayList* getDisplayList(DisplayList* displayList);
 
     void setViewport(int width, int height);
     void prepareDirty(float left, float top, float right, float bottom, bool opaque);
@@ -474,8 +474,6 @@
 
     SkWriter32 mWriter;
 
-    DisplayList *mDisplayList;
-
     int mRestoreSaveCount;
 
     friend class DisplayList;
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 412552e..0e8ae61 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -310,35 +310,21 @@
         int operation, ...)
 {
     switch (operation) {
-        case NATIVE_WINDOW_SET_USAGE:
-            // TODO: we should implement this
-            return NO_ERROR;
         case NATIVE_WINDOW_CONNECT:
-            // TODO: we should implement this
-            return NO_ERROR;
         case NATIVE_WINDOW_DISCONNECT:
-            // TODO: we should implement this
-            return NO_ERROR;
-        case NATIVE_WINDOW_LOCK:
-            return INVALID_OPERATION;
-        case NATIVE_WINDOW_UNLOCK_AND_POST:
-            return INVALID_OPERATION;
-        case NATIVE_WINDOW_SET_CROP:
-            return INVALID_OPERATION;
-        case NATIVE_WINDOW_SET_BUFFER_COUNT:
-            // TODO: we should implement this
-            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_USAGE:
         case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
-            return INVALID_OPERATION;
-        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
-            return INVALID_OPERATION;
-        case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
-            return INVALID_OPERATION;
         case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
-            return INVALID_OPERATION;
         case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
-            // TODO: we should implement this
+        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+            // TODO: we should implement these
             return NO_ERROR;
+
+        case NATIVE_WINDOW_LOCK:
+        case NATIVE_WINDOW_UNLOCK_AND_POST:
+        case NATIVE_WINDOW_SET_CROP:
+        case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
         case NATIVE_WINDOW_SET_SCALING_MODE:
             return INVALID_OPERATION;
     }
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index ed6e3c7..a11fb80 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -228,6 +228,7 @@
                 NATIVE_WINDOW_API_MEDIA);
 
         if (err != OK) {
+            LOGE("setVideoSurface failed: %d", err);
             // 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.
@@ -277,6 +278,7 @@
                 NATIVE_WINDOW_API_MEDIA);
 
         if (err != OK) {
+            LOGE("setVideoSurfaceTexture failed: %d", err);
             // 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.
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e17e1e8..3a3c082 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -42,6 +42,7 @@
         SampleTable.cpp                   \
         StagefrightMediaScanner.cpp       \
         StagefrightMetadataRetriever.cpp  \
+        SurfaceMediaSource.cpp            \
         ThrottledSource.cpp               \
         TimeSource.cpp                    \
         TimedEventQueue.cpp               \
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 77a6602..4edb613 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -185,7 +185,8 @@
       mFinalStatus(OK),
       mLastAccessPos(0),
       mFetching(true),
-      mLastFetchTimeUs(-1) {
+      mLastFetchTimeUs(-1),
+      mNumRetriesLeft(kMaxNumRetries) {
     mLooper->setName("NuCachedSource2");
     mLooper->registerHandler(mReflector);
     mLooper->start();
@@ -254,7 +255,27 @@
 void NuCachedSource2::fetchInternal() {
     LOGV("fetchInternal");
 
-    CHECK_EQ(mFinalStatus, (status_t)OK);
+    {
+        Mutex::Autolock autoLock(mLock);
+        CHECK(mFinalStatus == OK || mNumRetriesLeft > 0);
+
+        if (mFinalStatus != OK) {
+            --mNumRetriesLeft;
+
+            status_t err =
+                mSource->reconnectAtOffset(mCacheOffset + mCache->totalSize());
+
+            if (err == ERROR_UNSUPPORTED) {
+                mNumRetriesLeft = 0;
+                return;
+            } else if (err != OK) {
+                LOGI("The attempt to reconnect failed, %d retries remaining",
+                     mNumRetriesLeft);
+
+                return;
+            }
+        }
+    }
 
     PageCache::Page *page = mCache->acquirePage();
 
@@ -264,14 +285,23 @@
     Mutex::Autolock autoLock(mLock);
 
     if (n < 0) {
-        LOGE("source returned error %ld", n);
+        LOGE("source returned error %ld, %d retries left", n, mNumRetriesLeft);
         mFinalStatus = n;
         mCache->releasePage(page);
     } else if (n == 0) {
         LOGI("ERROR_END_OF_STREAM");
+
+        mNumRetriesLeft = 0;
         mFinalStatus = ERROR_END_OF_STREAM;
+
         mCache->releasePage(page);
     } else {
+        if (mFinalStatus != OK) {
+            LOGI("retrying a previously failed read succeeded.");
+        }
+        mNumRetriesLeft = kMaxNumRetries;
+        mFinalStatus = OK;
+
         page->mSize = n;
         mCache->appendPage(page);
     }
@@ -280,7 +310,7 @@
 void NuCachedSource2::onFetch() {
     LOGV("onFetch");
 
-    if (mFinalStatus != OK) {
+    if (mFinalStatus != OK && mNumRetriesLeft == 0) {
         LOGV("EOS reached, done prefetching for now");
         mFetching = false;
     }
@@ -308,8 +338,19 @@
         restartPrefetcherIfNecessary_l();
     }
 
-    (new AMessage(kWhatFetchMore, mReflector->id()))->post(
-            mFetching ? 0 : 100000ll);
+    int64_t delayUs;
+    if (mFetching) {
+        if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+            // We failed this time and will try again in 3 seconds.
+            delayUs = 3000000ll;
+        } else {
+            delayUs = 0;
+        }
+    } else {
+        delayUs = 100000ll;
+    }
+
+    (new AMessage(kWhatFetchMore, mReflector->id()))->post(delayUs);
 }
 
 void NuCachedSource2::onRead(const sp<AMessage> &msg) {
@@ -345,7 +386,7 @@
         bool ignoreLowWaterThreshold, bool force) {
     static const size_t kGrayArea = 1024 * 1024;
 
-    if (mFetching || mFinalStatus != OK) {
+    if (mFetching || (mFinalStatus != OK && mNumRetriesLeft == 0)) {
         return;
     }
 
@@ -427,6 +468,12 @@
 
 size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) {
     *finalStatus = mFinalStatus;
+
+    if (mFinalStatus != OK && mNumRetriesLeft > 0) {
+        // Pretend that everything is fine until we're out of retries.
+        *finalStatus = OK;
+    }
+
     off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
     if (mLastAccessPos < lastBytePosCached) {
         return lastBytePosCached - mLastAccessPos;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
new file mode 100644
index 0000000..db208dd
--- /dev/null
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -0,0 +1,752 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "SurfaceMediaSource"
+
+#include <media/stagefright/SurfaceMediaSource.h>
+#include <ui/GraphicBuffer.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/openmax/OMX_IVCommon.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <surfaceflinger/IGraphicBufferAlloc.h>
+#include <OMX_Component.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) :
+    mDefaultWidth(bufW),
+    mDefaultHeight(bufH),
+    mPixelFormat(0),
+    mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
+    mClientBufferCount(0),
+    mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
+    mCurrentSlot(INVALID_BUFFER_SLOT),
+    mCurrentTimestamp(0),
+    mSynchronousMode(true),
+    mConnectedApi(NO_CONNECTED_API),
+    mFrameRate(30),
+    mStarted(false)     {
+    LOGV("SurfaceMediaSource::SurfaceMediaSource");
+    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+}
+
+SurfaceMediaSource::~SurfaceMediaSource() {
+    LOGV("SurfaceMediaSource::~SurfaceMediaSource");
+    if (mStarted) {
+        stop();
+    }
+    freeAllBuffers();
+}
+
+size_t SurfaceMediaSource::getQueuedCount() const {
+    Mutex::Autolock lock(mMutex);
+    return mQueue.size();
+}
+
+status_t SurfaceMediaSource::setBufferCountServerLocked(int bufferCount) {
+    if (bufferCount > NUM_BUFFER_SLOTS)
+        return BAD_VALUE;
+
+    // special-case, nothing to do
+    if (bufferCount == mBufferCount)
+        return OK;
+
+    if (!mClientBufferCount &&
+        bufferCount >= mBufferCount) {
+        // easy, we just have more buffers
+        mBufferCount = bufferCount;
+        mServerBufferCount = bufferCount;
+        mDequeueCondition.signal();
+    } else {
+        // we're here because we're either
+        // - reducing the number of available buffers
+        // - or there is a client-buffer-count in effect
+
+        // less than 2 buffers is never allowed
+        if (bufferCount < 2)
+            return BAD_VALUE;
+
+        // when there is non client-buffer-count in effect, the client is not
+        // allowed to dequeue more than one buffer at a time,
+        // so the next time they dequeue a buffer, we know that they don't
+        // own one. the actual resizing will happen during the next
+        // dequeueBuffer.
+
+        mServerBufferCount = bufferCount;
+    }
+    return OK;
+}
+
+// Called from the consumer side
+status_t SurfaceMediaSource::setBufferCountServer(int bufferCount) {
+    Mutex::Autolock lock(mMutex);
+    return setBufferCountServerLocked(bufferCount);
+}
+
+status_t SurfaceMediaSource::setBufferCount(int bufferCount) {
+    LOGV("SurfaceMediaSource::setBufferCount");
+    if (bufferCount > NUM_BUFFER_SLOTS) {
+        LOGE("setBufferCount: bufferCount is larger than the number of buffer slots");
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    // Error out if the user has dequeued buffers
+    for (int i = 0 ; i < mBufferCount ; i++) {
+        if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
+            LOGE("setBufferCount: client owns some buffers");
+            return INVALID_OPERATION;
+        }
+    }
+
+    if (bufferCount == 0) {
+        const int minBufferSlots = mSynchronousMode ?
+                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+        mClientBufferCount = 0;
+        bufferCount = (mServerBufferCount >= minBufferSlots) ?
+                mServerBufferCount : minBufferSlots;
+        return setBufferCountServerLocked(bufferCount);
+    }
+
+    // We don't allow the client to set a buffer-count less than
+    // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it.
+    if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) {
+        return BAD_VALUE;
+    }
+
+    // here we're guaranteed that the client doesn't have dequeued buffers
+    // and will release all of its buffer references.
+    freeAllBuffers();
+    mBufferCount = bufferCount;
+    mClientBufferCount = bufferCount;
+    mCurrentSlot = INVALID_BUFFER_SLOT;
+    mQueue.clear();
+    mDequeueCondition.signal();
+    return OK;
+}
+
+sp<GraphicBuffer> SurfaceMediaSource::requestBuffer(int buf) {
+    LOGV("SurfaceMediaSource::requestBuffer");
+    Mutex::Autolock lock(mMutex);
+    if (buf < 0 || mBufferCount <= buf) {
+        LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, buf);
+        return 0;
+    }
+    mSlots[buf].mRequestBufferCalled = true;
+    return mSlots[buf].mGraphicBuffer;
+}
+
+status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
+                                            uint32_t format, uint32_t usage) {
+    LOGV("dequeueBuffer");
+
+
+    // Check for the buffer size- the client should just use the
+    // default width and height, and not try to set those.
+    // This is needed since
+    // the getFormat() returns mDefaultWidth/ Height for the OMX. It is
+    // queried by OMX in the beginning and not every time a frame comes.
+    // Not sure if there is  a way to update the
+    // frame size while recording. So as of now, the client side
+    // sets the default values via the constructor, and the encoder is
+    // setup to encode frames of that size
+    // The design might need to change in the future.
+    // TODO: Currently just uses mDefaultWidth/Height. In the future
+    // we might declare mHeight and mWidth and check against those here.
+    if ((w != 0) || (h != 0)) {
+        LOGE("dequeuebuffer: invalid buffer size! Req: %dx%d, Found: %dx%d",
+                mDefaultWidth, mDefaultHeight, w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+
+    status_t returnFlags(OK);
+
+    int found, foundSync;
+    int dequeuedCount = 0;
+    bool tryAgain = true;
+    while (tryAgain) {
+        // We need to wait for the FIFO to drain if the number of buffer
+        // needs to change.
+        //
+        // The condition "number of buffer needs to change" is true if
+        // - the client doesn't care about how many buffers there are
+        // - AND the actual number of buffer is different from what was
+        //   set in the last setBufferCountServer()
+        //                         - OR -
+        //   setBufferCountServer() was set to a value incompatible with
+        //   the synchronization mode (for instance because the sync mode
+        //   changed since)
+        //
+        // As long as this condition is true AND the FIFO is not empty, we
+        // wait on mDequeueCondition.
+
+        int minBufferCountNeeded = mSynchronousMode ?
+                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+
+        if (!mClientBufferCount &&
+                ((mServerBufferCount != mBufferCount) ||
+                        (mServerBufferCount < minBufferCountNeeded))) {
+            // wait for the FIFO to drain
+            while (!mQueue.isEmpty()) {
+                LOGV("Waiting for the FIFO to drain");
+                mDequeueCondition.wait(mMutex);
+            }
+            // need to check again since the mode could have changed
+            // while we were waiting
+            minBufferCountNeeded = mSynchronousMode ?
+                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+        }
+
+        if (!mClientBufferCount &&
+                ((mServerBufferCount != mBufferCount) ||
+                        (mServerBufferCount < minBufferCountNeeded))) {
+            // here we're guaranteed that mQueue is empty
+            freeAllBuffers();
+            mBufferCount = mServerBufferCount;
+            if (mBufferCount < minBufferCountNeeded)
+                mBufferCount = minBufferCountNeeded;
+            mCurrentSlot = INVALID_BUFFER_SLOT;
+            returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+        }
+
+        // look for a free buffer to give to the client
+        found = INVALID_BUFFER_SLOT;
+        foundSync = INVALID_BUFFER_SLOT;
+        dequeuedCount = 0;
+        for (int i = 0; i < mBufferCount; i++) {
+            const int state = mSlots[i].mBufferState;
+            if (state == BufferSlot::DEQUEUED) {
+                dequeuedCount++;
+                continue; // won't be continuing if could
+                // dequeue a non 'FREE' current slot like
+                // that in SurfaceTexture
+            }
+            // In case of Encoding, we do not deque the mCurrentSlot buffer
+            //  since we follow synchronous mode (unlike possibly in
+            //  SurfaceTexture that could be using the asynch mode
+            //  or has some mechanism in GL to be able to wait till the
+            //  currentslot is done using the data)
+            // Here, we have to wait for the MPEG4Writer(or equiv)
+            // to tell us when it's done using the current buffer
+            if (state == BufferSlot::FREE) {
+                foundSync = i;
+                // Unlike that in SurfaceTexture,
+                // We don't need to worry if it is the
+                // currentslot or not as it is in state FREE
+                found = i;
+                break;
+            }
+        }
+
+        // clients are not allowed to dequeue more than one buffer
+        // if they didn't set a buffer count.
+        if (!mClientBufferCount && dequeuedCount) {
+            return -EINVAL;
+        }
+
+        // See whether a buffer has been queued since the last setBufferCount so
+        // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
+        bool bufferHasBeenQueued = mCurrentSlot != INVALID_BUFFER_SLOT;
+        if (bufferHasBeenQueued) {
+            // make sure the client is not trying to dequeue more buffers
+            // than allowed.
+            const int avail = mBufferCount - (dequeuedCount+1);
+            if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
+                LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)",
+                        MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
+                        dequeuedCount);
+                return -EBUSY;
+            }
+        }
+
+        // we're in synchronous mode and didn't find a buffer, we need to wait
+        // for for some buffers to be consumed
+        tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
+        if (tryAgain) {
+            LOGW("Waiting..In synchronous mode and no buffer to dQ");
+            mDequeueCondition.wait(mMutex);
+        }
+    }
+
+    if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
+        // foundSync guaranteed to be != INVALID_BUFFER_SLOT
+        found = foundSync;
+    }
+
+    if (found == INVALID_BUFFER_SLOT) {
+        return -EBUSY;
+    }
+
+    const int buf = found;
+    *outBuf = found;
+
+    const bool useDefaultSize = !w && !h;
+    if (useDefaultSize) {
+        // use the default size
+        w = mDefaultWidth;
+        h = mDefaultHeight;
+    }
+
+    const bool updateFormat = (format != 0);
+    if (!updateFormat) {
+        // keep the current (or default) format
+        format = mPixelFormat;
+    }
+
+    // buffer is now in DEQUEUED (but can also be current at the same time,
+    // if we're in synchronous mode)
+    mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+    const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+    if ((buffer == NULL) ||
+        (uint32_t(buffer->width)  != w) ||
+        (uint32_t(buffer->height) != h) ||
+        (uint32_t(buffer->format) != format) ||
+        ((uint32_t(buffer->usage) & usage) != usage)) {
+            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+            status_t error;
+            sp<GraphicBuffer> graphicBuffer(
+                    mGraphicBufferAlloc->createGraphicBuffer(
+                                    w, h, format, usage, &error));
+            if (graphicBuffer == 0) {
+                LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
+                return error;
+            }
+            if (updateFormat) {
+                mPixelFormat = format;
+            }
+            mSlots[buf].mGraphicBuffer = graphicBuffer;
+            mSlots[buf].mRequestBufferCalled = false;
+            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+    }
+    return returnFlags;
+}
+
+status_t SurfaceMediaSource::setSynchronousMode(bool enabled) {
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = OK;
+    if (!enabled) {
+        // going to asynchronous mode, drain the queue
+        while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
+            mDequeueCondition.wait(mMutex);
+        }
+    }
+
+    if (mSynchronousMode != enabled) {
+        // - if we're going to asynchronous mode, the queue is guaranteed to be
+        // empty here
+        // - if the client set the number of buffers, we're guaranteed that
+        // we have at least 3 (because we don't allow less)
+        mSynchronousMode = enabled;
+        mDequeueCondition.signal();
+    }
+    return err;
+}
+
+status_t SurfaceMediaSource::connect(int api) {
+    LOGV("SurfaceMediaSource::connect");
+    Mutex::Autolock lock(mMutex);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi != NO_CONNECTED_API) {
+                err = -EINVAL;
+            } else {
+                mConnectedApi = api;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+status_t SurfaceMediaSource::disconnect(int api) {
+    LOGV("SurfaceMediaSource::disconnect");
+    Mutex::Autolock lock(mMutex);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi == api) {
+                mConnectedApi = NO_CONNECTED_API;
+            } else {
+                err = -EINVAL;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+status_t SurfaceMediaSource::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    LOGV("queueBuffer");
+
+    Mutex::Autolock lock(mMutex);
+    if (buf < 0 || buf >= mBufferCount) {
+        LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, buf);
+        return -EINVAL;
+    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+        LOGE("queueBuffer: slot %d is not owned by the client (state=%d)",
+                buf, mSlots[buf].mBufferState);
+        return -EINVAL;
+    } else if (!mSlots[buf].mRequestBufferCalled) {
+        LOGE("queueBuffer: slot %d was enqueued without requesting a "
+                "buffer", buf);
+        return -EINVAL;
+    }
+
+    if (mSynchronousMode) {
+        // in synchronous mode we queue all buffers in a FIFO
+        mQueue.push_back(buf);
+        LOGV("Client queued buffer on slot: %d, Q size = %d",
+                                                buf, mQueue.size());
+    } else {
+        // in asynchronous mode we only keep the most recent buffer
+        if (mQueue.empty()) {
+            mQueue.push_back(buf);
+        } else {
+            Fifo::iterator front(mQueue.begin());
+            // buffer currently queued is freed
+            mSlots[*front].mBufferState = BufferSlot::FREE;
+            // and we record the new buffer index in the queued list
+            *front = buf;
+        }
+    }
+
+    mSlots[buf].mBufferState = BufferSlot::QUEUED;
+    mSlots[buf].mTimestamp = timestamp;
+    // TODO: (Confirm) Don't want to signal dequeue here.
+    // May be just in asynchronous mode?
+    // mDequeueCondition.signal();
+
+    // Once the queuing is done, we need to let the listener
+    // and signal the buffer consumer (encoder) know that a
+    // buffer is available
+    onFrameReceivedLocked();
+
+    *outWidth = mDefaultWidth;
+    *outHeight = mDefaultHeight;
+    *outTransform = 0;
+
+    return OK;
+}
+
+
+// onFrameReceivedLocked informs the buffer consumers (StageFrightRecorder)
+// or listeners that a frame has been received
+// It is supposed to be called only from queuebuffer.
+// The buffer is NOT made available for dequeueing immediately. We need to
+// wait to hear from StageFrightRecorder to set the buffer FREE
+// Make sure this is called when the mutex is locked
+status_t SurfaceMediaSource::onFrameReceivedLocked() {
+    LOGV("On Frame Received");
+    // Signal the encoder that a new frame has arrived
+    mFrameAvailableCondition.signal();
+
+    // call back the listener
+    // TODO: The listener may not be needed in SurfaceMediaSource at all.
+    // This can be made a SurfaceTexture specific thing
+    sp<FrameAvailableListener> listener;
+    if (mSynchronousMode || mQueue.empty()) {
+        listener = mFrameAvailableListener;
+    }
+
+    if (listener != 0) {
+        listener->onFrameAvailable();
+    }
+    return OK;
+}
+
+
+void SurfaceMediaSource::cancelBuffer(int buf) {
+    LOGV("SurfaceMediaSource::cancelBuffer");
+    Mutex::Autolock lock(mMutex);
+    if (buf < 0 || buf >= mBufferCount) {
+        LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, buf);
+        return;
+    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+        LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
+                buf, mSlots[buf].mBufferState);
+        return;
+    }
+    mSlots[buf].mBufferState = BufferSlot::FREE;
+    mDequeueCondition.signal();
+}
+
+nsecs_t SurfaceMediaSource::getTimestamp() {
+    LOGV("SurfaceMediaSource::getTimestamp");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTimestamp;
+}
+
+
+void SurfaceMediaSource::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& listener) {
+    LOGV("SurfaceMediaSource::setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
+sp<IBinder> SurfaceMediaSource::getAllocator() {
+    LOGV("getAllocator");
+    return mGraphicBufferAlloc->asBinder();
+}
+
+
+void SurfaceMediaSource::freeAllBuffers() {
+    LOGV("freeAllBuffers");
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i].mGraphicBuffer = 0;
+        mSlots[i].mBufferState = BufferSlot::FREE;
+    }
+}
+
+sp<GraphicBuffer> SurfaceMediaSource::getCurrentBuffer() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentBuf;
+}
+
+int SurfaceMediaSource::query(int what, int* outValue)
+{
+    LOGV("query");
+    Mutex::Autolock lock(mMutex);
+    int value;
+    switch (what) {
+    case NATIVE_WINDOW_WIDTH:
+        value = mDefaultWidth;
+        if (!mDefaultWidth && !mDefaultHeight && mCurrentBuf != 0)
+            value = mCurrentBuf->width;
+        break;
+    case NATIVE_WINDOW_HEIGHT:
+        value = mDefaultHeight;
+        if (!mDefaultWidth && !mDefaultHeight && mCurrentBuf != 0)
+            value = mCurrentBuf->height;
+        break;
+    case NATIVE_WINDOW_FORMAT:
+        value = mPixelFormat;
+        break;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        value = mSynchronousMode ?
+                (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    outValue[0] = value;
+    return NO_ERROR;
+}
+
+void SurfaceMediaSource::dump(String8& result) const
+{
+    char buffer[1024];
+    dump(result, "", buffer, 1024);
+}
+
+void SurfaceMediaSource::dump(String8& result, const char* prefix,
+        char* buffer, size_t SIZE) const
+{
+    Mutex::Autolock _l(mMutex);
+    snprintf(buffer, SIZE,
+            "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
+            "mPixelFormat=%d, \n",
+            prefix, mBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight,
+            mPixelFormat);
+    result.append(buffer);
+
+    String8 fifo;
+    int fifoSize = 0;
+    Fifo::const_iterator i(mQueue.begin());
+    while (i != mQueue.end()) {
+        snprintf(buffer, SIZE, "%02d ", *i++);
+        fifoSize++;
+        fifo.append(buffer);
+    }
+
+    result.append(buffer);
+
+    struct {
+        const char * operator()(int state) const {
+            switch (state) {
+                case BufferSlot::DEQUEUED: return "DEQUEUED";
+                case BufferSlot::QUEUED: return "QUEUED";
+                case BufferSlot::FREE: return "FREE";
+                default: return "Unknown";
+            }
+        }
+    } stateName;
+
+    for (int i = 0; i < mBufferCount; i++) {
+        const BufferSlot& slot(mSlots[i]);
+        snprintf(buffer, SIZE,
+                "%s%s[%02d] state=%-8s, "
+                "timestamp=%lld\n",
+                prefix, (i==mCurrentSlot)?">":" ", i, stateName(slot.mBufferState),
+                slot.mTimestamp
+        );
+        result.append(buffer);
+    }
+}
+
+void SurfaceMediaSource::setFrameRate(uint32_t fps)
+{
+    Mutex::Autolock lock(mMutex);
+    mFrameRate = fps;
+}
+
+uint32_t SurfaceMediaSource::getFrameRate( ) const {
+    Mutex::Autolock lock(mMutex);
+    return mFrameRate;
+}
+
+status_t SurfaceMediaSource::start(MetaData *params)
+{
+    LOGV("start");
+    Mutex::Autolock lock(mMutex);
+    CHECK(!mStarted);
+    mStarted = true;
+    return OK;
+}
+
+
+status_t SurfaceMediaSource::stop()
+{
+    LOGV("Stop");
+
+    Mutex::Autolock lock(mMutex);
+    // TODO: Add waiting on mFrameCompletedCondition here?
+    mStarted = false;
+    mFrameAvailableCondition.signal();
+
+    return OK;
+}
+
+sp<MetaData> SurfaceMediaSource::getFormat()
+{
+    LOGV("getFormat");
+    Mutex::Autolock autoLock(mMutex);
+    sp<MetaData> meta = new MetaData;
+    // XXX: Check if this is right. or should we wait on some
+    // condition?
+    meta->setInt32(kKeyWidth, mDefaultWidth);
+    meta->setInt32(kKeyHeight, mDefaultHeight);
+    // The encoder format is set as an opaque colorformat
+    // The encoder will later find out the actual colorformat
+    // from the GL Frames itself.
+    meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque);
+    meta->setInt32(kKeyStride, mDefaultWidth);
+    meta->setInt32(kKeySliceHeight, mDefaultHeight);
+    meta->setInt32(kKeyFrameRate, mFrameRate);
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
+    return meta;
+}
+
+status_t SurfaceMediaSource::read( MediaBuffer **buffer,
+                                const ReadOptions *options)
+{
+    LOGV("Read. Size of queued buffer: %d", mQueue.size());
+    *buffer = NULL;
+
+    Mutex::Autolock autoLock(mMutex) ;
+    // If the recording has started and the queue is empty, then just
+    // wait here till the frames come in from the client side
+    while (mStarted && mQueue.empty()) {
+        LOGV("NO FRAMES! Recorder waiting for FrameAvailableCondition");
+        mFrameAvailableCondition.wait(mMutex);
+    }
+
+    // If the loop was exited as a result of stopping the recording,
+    // it is OK
+    if (!mStarted) {
+        return OK;
+    }
+
+    // Update the current buffer info
+    // TODO: mCurrentSlot can be made a bufferstate since there
+    // can be more than one "current" slots.
+    Fifo::iterator front(mQueue.begin());
+    mCurrentSlot = *front;
+    mCurrentBuf = mSlots[mCurrentSlot].mGraphicBuffer;
+    mCurrentTimestamp = mSlots[mCurrentSlot].mTimestamp;
+
+    // Pass the data to the MediaBuffer
+    // TODO: Change later to pass in only the metadata
+    *buffer = new MediaBuffer(mCurrentBuf);
+    (*buffer)->setObserver(this);
+    (*buffer)->add_ref();
+    (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp);
+
+    return OK;
+}
+
+void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
+    LOGV("signalBufferReturned");
+
+    bool foundBuffer = false;
+    Mutex::Autolock autoLock(mMutex);
+
+    if (!mStarted) {
+        LOGV("started = false. Nothing to do");
+        return;
+    }
+
+    for (Fifo::iterator it = mQueue.begin(); it != mQueue.end(); ++it) {
+        if (mSlots[*it].mGraphicBuffer  ==  buffer->graphicBuffer()) {
+            LOGV("Buffer %d returned. Setting it 'FREE'. New Queue size = %d",
+                    *it, mQueue.size()-1);
+            mSlots[*it].mBufferState = BufferSlot::FREE;
+            mQueue.erase(it);
+            buffer->setObserver(0);
+            buffer->release();
+            mDequeueCondition.signal();
+            mFrameCompleteCondition.signal();
+            foundBuffer = true;
+            break;
+        }
+    }
+
+    if (!foundBuffer) {
+        CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+    }
+}
+
+
+
+} // end of namespace android
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 588a74d..07a9eb8 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -25,6 +25,8 @@
 
 #include "support.h"
 
+#include <cutils/properties.h> // for property_get
+
 namespace android {
 
 ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
@@ -111,7 +113,7 @@
     mState = DISCONNECTED;
     mCondition.broadcast();
 
-    mURI.clear();
+    // mURI.clear();
 
     mIOResult = err;
 
@@ -150,9 +152,19 @@
     Mutex::Autolock autoLock(mLock);
 
     if (mState != CONNECTED) {
-        return ERROR_NOT_CONNECTED;
+        return INVALID_OPERATION;
     }
 
+#if 0
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.disable-net", value, 0)
+            && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
+        LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down.");
+        disconnect_l();
+        return ERROR_IO;
+    }
+#endif
+
     if (offset != mCurrentOffset) {
         AString tmp = mURI;
         KeyedVector<String8, String8> tmpHeaders = mHeaders;
@@ -236,7 +248,7 @@
     CHECK_EQ((int)mState, (int)DISCONNECTING);
 
     mState = DISCONNECTED;
-    mURI.clear();
+    // mURI.clear();
 
     mCondition.broadcast();
 
@@ -299,5 +311,21 @@
     }
 }
 
+status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mURI.empty()) {
+        return INVALID_OPERATION;
+    }
+
+    LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting...");
+    status_t err = connect_l(mURI.c_str(), &mHeaders, offset);
+    if (err != OK) {
+        LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err);
+    }
+
+    return err;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h
index d833e2e..18f8913 100644
--- a/media/libstagefright/include/ChromiumHTTPDataSource.h
+++ b/media/libstagefright/include/ChromiumHTTPDataSource.h
@@ -51,6 +51,8 @@
 
     virtual String8 getMIMEType() const;
 
+    virtual status_t reconnectAtOffset(off64_t offset);
+
 protected:
     virtual ~ChromiumHTTPDataSource();
 
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 2d6cb84..22b2855 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -77,6 +77,10 @@
         kWhatRead       = 'read',
     };
 
+    enum {
+        kMaxNumRetries = 10,
+    };
+
     sp<DataSource> mSource;
     sp<AHandlerReflector<NuCachedSource2> > mReflector;
     sp<ALooper> mLooper;
@@ -93,6 +97,8 @@
     bool mFetching;
     int64_t mLastFetchTimeUs;
 
+    int32_t mNumRetriesLeft;
+
     void onMessageReceived(const sp<AMessage> &msg);
     void onFetch();
     void onRead(const sp<AMessage> &msg);
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
new file mode 100644
index 0000000..3ea8f39
--- /dev/null
+++ b/media/libstagefright/tests/Android.mk
@@ -0,0 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_MODULE := SurfaceMediaSource_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    SurfaceMediaSource_test.cpp \
+	DummyRecorder.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libEGL \
+	libGLESv2 \
+	libandroid \
+	libbinder \
+	libcutils \
+	libgui \
+	libstlport \
+	libui \
+	libutils \
+	libstagefright \
+	libstagefright_omx \
+	libstagefright_foundation \
+
+LOCAL_STATIC_LIBRARIES := \
+	libgtest \
+	libgtest_main \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+	frameworks/base/media/libstagefright \
+	frameworks/base/media/libstagefright/include \
+	$(TOP)/frameworks/base/include/media/stagefright/openmax \
+
+include $(BUILD_EXECUTABLE)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/media/libstagefright/tests/DummyRecorder.cpp b/media/libstagefright/tests/DummyRecorder.cpp
new file mode 100644
index 0000000..8d75d6b
--- /dev/null
+++ b/media/libstagefright/tests/DummyRecorder.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "DummyRecorder"
+// #define LOG_NDEBUG 0
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include "DummyRecorder.h"
+
+#include <utils/Log.h>
+
+namespace android {
+
+// static
+void *DummyRecorder::threadWrapper(void *pthis) {
+    LOGV("ThreadWrapper: %p", pthis);
+    DummyRecorder *writer = static_cast<DummyRecorder *>(pthis);
+    writer->readFromSource();
+    return NULL;
+}
+
+
+status_t DummyRecorder::start() {
+    LOGV("Start");
+    mStarted = true;
+
+    mSource->start();
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    int err = pthread_create(&mThread, &attr, threadWrapper, this);
+    pthread_attr_destroy(&attr);
+
+    if (err) {
+        LOGE("Error creating thread!");
+        return -ENODEV;
+    }
+    return OK;
+}
+
+
+status_t DummyRecorder::stop() {
+    LOGV("Stop");
+    mStarted = false;
+
+    mSource->stop();
+    void *dummy;
+    pthread_join(mThread, &dummy);
+    status_t err = (status_t) dummy;
+
+    LOGV("Ending the reading thread");
+    return err;
+}
+
+// pretend to read the source buffers
+void DummyRecorder::readFromSource() {
+    LOGV("ReadFromSource");
+    if (!mStarted) {
+        return;
+    }
+
+    status_t err = OK;
+    MediaBuffer *buffer;
+    LOGV("A fake writer accessing the frames");
+    while (mStarted && (err = mSource->read(&buffer)) == OK){
+        // if not getting a valid buffer from source, then exit
+        if (buffer == NULL) {
+            return;
+        }
+        buffer->release();
+        buffer = NULL;
+    }
+}
+
+
+} // end of namespace android
diff --git a/media/libstagefright/tests/DummyRecorder.h b/media/libstagefright/tests/DummyRecorder.h
new file mode 100644
index 0000000..1cbea1b
--- /dev/null
+++ b/media/libstagefright/tests/DummyRecorder.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef DUMMY_RECORDER_H_
+#define DUMMY_RECORDER_H_
+
+#include <pthread.h>
+#include <utils/String8.h>
+#include <media/stagefright/foundation/ABase.h>
+
+
+namespace android {
+
+class MediaSource;
+class MediaBuffer;
+
+class DummyRecorder {
+    public:
+    // The media source from which this will receive frames
+    sp<MediaSource> mSource;
+    bool mStarted;
+    pthread_t mThread;
+
+    status_t start();
+    status_t stop();
+
+    // actual entry point for the thread
+    void readFromSource();
+
+    // static function to wrap the actual thread entry point
+    static void *threadWrapper(void *pthis);
+
+    DummyRecorder(const sp<MediaSource> &source) : mSource(source)
+                                                    , mStarted(false) {}
+    ~DummyRecorder( ) {}
+
+    private:
+
+    DISALLOW_EVIL_CONSTRUCTORS(DummyRecorder);
+};
+
+} // end of namespace android
+#endif
+
+
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
new file mode 100644
index 0000000..ce10812
--- /dev/null
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceMediaSource_test"
+// #define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+
+#include <media/stagefright/SurfaceMediaSource.h>
+
+#include <gui/SurfaceTextureClient.h>
+#include <ui/GraphicBuffer.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <binder/ProcessState.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <OMX_Component.h>
+
+#include "DummyRecorder.h"
+
+namespace android {
+
+
+class SurfaceMediaSourceTest : public ::testing::Test {
+public:
+
+    SurfaceMediaSourceTest( ): mYuvTexWidth(64), mYuvTexHeight(66) { }
+    sp<MPEG4Writer>  setUpWriter(OMXClient &client );
+    void oneBufferPass(int width, int height );
+    static void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) ;
+    static void fillYV12BufferRect(uint8_t* buf, int w, int h,
+                        int stride, const android_native_rect_t& rect) ;
+protected:
+
+    virtual void SetUp() {
+        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
+        mSMS->setSynchronousMode(true);
+        mSTC = new SurfaceTextureClient(mSMS);
+        mANW = mSTC;
+
+    }
+
+
+    virtual void TearDown() {
+        mSMS.clear();
+        mSTC.clear();
+        mANW.clear();
+    }
+
+    const int mYuvTexWidth;//  = 64;
+    const int mYuvTexHeight;// = 66;
+
+    sp<SurfaceMediaSource> mSMS;
+    sp<SurfaceTextureClient> mSTC;
+    sp<ANativeWindow> mANW;
+
+};
+
+void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) {
+    LOGV("One Buffer Pass");
+    ANativeWindowBuffer* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // Fill the buffer with the a checkerboard pattern
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride());
+    buf->unlock();
+
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+}
+
+sp<MPEG4Writer> SurfaceMediaSourceTest::setUpWriter(OMXClient &client ) {
+    // Writing to a file
+    const char *fileName = "/sdcard/outputSurfEnc.mp4";
+    sp<MetaData> enc_meta = new MetaData;
+    enc_meta->setInt32(kKeyBitRate, 300000);
+    enc_meta->setInt32(kKeyFrameRate, 30);
+
+    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+
+    sp<MetaData> meta = mSMS->getFormat();
+
+    int32_t width, height, stride, sliceHeight, colorFormat;
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+    CHECK(meta->findInt32(kKeyStride, &stride));
+    CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+    CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
+
+    enc_meta->setInt32(kKeyWidth, width);
+    enc_meta->setInt32(kKeyHeight, height);
+    enc_meta->setInt32(kKeyIFramesInterval, 1);
+    enc_meta->setInt32(kKeyStride, stride);
+    enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+    // TODO: overwriting the colorformat since the format set by GRAlloc
+    // could be wrong or not be read by OMX
+    enc_meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
+    // colorFormat);
+
+
+    sp<MediaSource> encoder =
+        OMXCodec::Create(
+                client.interface(), enc_meta, true /* createEncoder */, mSMS);
+
+    sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
+    writer->addSource(encoder);
+
+    return writer;
+}
+
+// Fill a YV12 buffer with a multi-colored checkerboard pattern
+void SurfaceMediaSourceTest::fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
+    const int blockWidth = w > 16 ? w / 16 : 1;
+    const int blockHeight = h > 16 ? h / 16 : 1;
+    const int yuvTexOffsetY = 0;
+    int yuvTexStrideY = stride;
+    int yuvTexOffsetV = yuvTexStrideY * h;
+    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
+    int yuvTexStrideU = yuvTexStrideV;
+    for (int x = 0; x < w; x++) {
+        for (int y = 0; y < h; y++) {
+            int parityX = (x / blockWidth) & 1;
+            int parityY = (y / blockHeight) & 1;
+            unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
+            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+            if (x < w / 2 && y < h / 2) {
+                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
+                if (x * 2 < w / 2 && y * 2 < h / 2) {
+                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
+                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
+                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
+                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
+                        intensity;
+                }
+            }
+        }
+    }
+}
+
+// Fill a YV12 buffer with red outside a given rectangle and green inside it.
+void SurfaceMediaSourceTest::fillYV12BufferRect(uint8_t* buf, int w,
+                  int h, int stride, const android_native_rect_t& rect) {
+    const int yuvTexOffsetY = 0;
+    int yuvTexStrideY = stride;
+    int yuvTexOffsetV = yuvTexStrideY * h;
+    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
+    int yuvTexStrideU = yuvTexStrideV;
+    for (int x = 0; x < w; x++) {
+        for (int y = 0; y < h; y++) {
+            bool inside = rect.left <= x && x < rect.right &&
+                    rect.top <= y && y < rect.bottom;
+            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
+            if (x < w / 2 && y < h / 2) {
+                bool inside = rect.left <= 2*x && 2*x < rect.right &&
+                        rect.top <= 2*y && 2*y < rect.bottom;
+                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
+                buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
+                                                inside ? 16 : 255;
+            }
+        }
+    }
+}  ///////// End of class SurfaceMediaSourceTest
+
+///////////////////////////////////////////////////////////////////
+// Class to imitate the recording     /////////////////////////////
+// ////////////////////////////////////////////////////////////////
+struct SimpleDummyRecorder {
+        sp<MediaSource> mSource;
+
+        SimpleDummyRecorder
+                (const sp<MediaSource> &source): mSource(source) {}
+
+        status_t start() { return mSource->start();}
+        status_t stop()  { return mSource->stop();}
+
+        // fakes reading from a media source
+        status_t readFromSource() {
+            MediaBuffer *buffer;
+            status_t err = mSource->read(&buffer);
+            if (err != OK) {
+                return err;
+            }
+            buffer->release();
+            buffer = NULL;
+            return OK;
+        }
+};
+
+///////////////////////////////////////////////////////////////////
+//           TESTS
+// Just pass one buffer from the native_window to the SurfaceMediaSource
+TEST_F(SurfaceMediaSourceTest, EncodingFromCpuFilledYV12BufferNpotOneBufferPass) {
+    LOGV("Testing OneBufferPass ******************************");
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            0, 0, HAL_PIXEL_FORMAT_YV12));
+                                // OMX_COLOR_FormatYUV420Planar)); // ));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    oneBufferPass(mYuvTexWidth, mYuvTexHeight);
+}
+
+// Pass the buffer with the wrong height and weight and should not be accepted
+TEST_F(SurfaceMediaSourceTest, EncodingFromCpuFilledYV12BufferNpotWrongSizeBufferPass) {
+    LOGV("Testing Wrong size BufferPass ******************************");
+
+    // setting the client side buffer size different than the server size
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+             10, 10, HAL_PIXEL_FORMAT_YV12));
+                                // OMX_COLOR_FormatYUV420Planar)); // ));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    ANativeWindowBuffer* anb;
+
+    // make sure we get an error back when dequeuing!
+    ASSERT_NE(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+}
+
+
+// pass multiple buffers from the native_window the SurfaceMediaSource
+// A dummy writer is used to simulate actual MPEG4Writer
+TEST_F(SurfaceMediaSourceTest,  EncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
+    LOGV("Testing MultiBufferPass, Dummy Recorder *********************");
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            0, 0, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+    SimpleDummyRecorder writer(mSMS);
+    writer.start();
+
+    int32_t nFramesCount = 0;
+    while (nFramesCount < 300) {
+        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
+
+        ASSERT_EQ(NO_ERROR, writer.readFromSource());
+
+        nFramesCount++;
+    }
+    writer.stop();
+}
+
+// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
+// A dummy writer is used to simulate actual MPEG4Writer
+TEST_F(SurfaceMediaSourceTest,  EncodingFromCpuFilledYV12BufferNpotMultiBufferPassLag) {
+    LOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            0, 0, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+    SimpleDummyRecorder writer(mSMS);
+    writer.start();
+
+    int32_t nFramesCount = 1;
+    const int FRAMES_LAG = mSMS->getBufferCount() - 1;
+    while (nFramesCount <= 300) {
+        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
+        // Forcing the writer to lag behind a few frames
+        if (nFramesCount > FRAMES_LAG) {
+            ASSERT_EQ(NO_ERROR, writer.readFromSource());
+        }
+        nFramesCount++;
+    }
+    writer.stop();
+}
+
+// pass multiple buffers from the native_window the SurfaceMediaSource
+// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
+TEST_F(SurfaceMediaSourceTest, EncodingFromCpuFilledYV12BufferNpotMultiBufferPassThreaded) {
+    LOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            0, 0, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    DummyRecorder writer(mSMS);
+    writer.start();
+
+    int32_t nFramesCount = 0;
+    while (nFramesCount <= 300) {
+        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
+
+        nFramesCount++;
+    }
+    writer.stop();
+}
+
+// Test to examine the actual encoding. Temporarily disabled till the
+// colorformat and encoding from GRAlloc data is resolved
+TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuFilledYV12BufferNpotWrite) {
+    LOGV("Testing the whole pipeline with actual Recorder");
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            0, 0, HAL_PIXEL_FORMAT_YV12)); // OMX_COLOR_FormatYUV420Planar)); // ));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    OMXClient client;
+    CHECK_EQ(OK, client.connect());
+
+    sp<MPEG4Writer> writer = setUpWriter(client);
+    int64_t start = systemTime();
+    CHECK_EQ(OK, writer->start());
+
+    int32_t nFramesCount = 0;
+    while (nFramesCount <= 300) {
+        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
+        nFramesCount++;
+    }
+
+    CHECK_EQ(OK, writer->stop());
+    writer.clear();
+    int64_t end = systemTime();
+    client.disconnect();
+}
+
+
+} // namespace android
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 5298f2e..d7d7817 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -34,7 +34,7 @@
     <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
 
     <!-- Whether or not we show the number in the bar. -->
-    <bool name="config_statusBarShowNumber">true</bool>
+    <bool name="config_statusBarShowNumber">false</bool>
 
     <!-- How many icons may be shown at once in the system bar. Includes any
          slots that may be reused for things like IME control. -->
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index cca7947..ea54445 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -329,6 +329,7 @@
 
 
         mRecentsGlowView = findViewById(R.id.recents_glow);
+        mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
         mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, this);
         mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
         mRecentsDismissButton.setOnClickListener(new OnClickListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index b4d2a14..d5885bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -148,6 +148,11 @@
                                 "now sliding child %d: %s (touchY=%.1f, rowHeight=%d, count=%d)",
                                 childIdx, mSlidingChild, mInitialTouchY, mRowHeight, count));
                         }
+
+
+                        // We need to prevent the surrounding ScrollView from intercepting us now;
+                        // the scroll position will be locked while we swipe
+                        requestDisallowInterceptTouchEvent(true);
                     }
                 }
                 break;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b963b13..e0debf7 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -388,6 +388,11 @@
         st.isHandled = false;
         mPreparedPanel = st;
 
+        if (st.frozenActionViewState != null) {
+            st.menu.restoreActionViewStates(st.frozenActionViewState);
+            st.frozenActionViewState = null;
+        }
+
         return true;
     }
 
@@ -652,7 +657,13 @@
     @Override
     public void invalidatePanelMenu(int featureId) {
         PanelFeatureState st = getPanelState(featureId, true);
+        Bundle savedActionViewStates = null;
         if (st.menu != null) {
+            savedActionViewStates = new Bundle();
+            st.menu.saveActionViewStates(savedActionViewStates);
+            if (savedActionViewStates.size() > 0) {
+                st.frozenActionViewState = savedActionViewStates;
+            }
             st.menu.clear();
         }
         st.refreshMenuContent = true;
@@ -3024,6 +3035,12 @@
          */
         Bundle frozenMenuState;
 
+        /**
+         * Contains the state of associated action views when told to freeze.
+         * These are saved across invalidations.
+         */
+        Bundle frozenActionViewState;
+
         PanelFeatureState(int featureId) {
             this.featureId = featureId;
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ad6cebb..ae13ab5 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -166,22 +166,22 @@
     static final int SYSTEM_DIALOG_LAYER = 6;
     // toasts and the plugged-in battery thing
     static final int TOAST_LAYER = 7;
-    static final int STATUS_BAR_LAYER = 8;
-    static final int STATUS_BAR_PANEL_LAYER = 9;
     // SIM errors and unlock.  Not sure if this really should be in a high layer.
-    static final int PRIORITY_PHONE_LAYER = 10;
+    static final int PRIORITY_PHONE_LAYER = 8;
     // like the ANR / app crashed dialogs
-    static final int SYSTEM_ALERT_LAYER = 11;
+    static final int SYSTEM_ALERT_LAYER = 9;
     // system-level error dialogs
-    static final int SYSTEM_ERROR_LAYER = 12;
+    static final int SYSTEM_ERROR_LAYER = 10;
     // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_LAYER = 13;
+    static final int INPUT_METHOD_LAYER = 11;
     // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_DIALOG_LAYER = 14;
+    static final int INPUT_METHOD_DIALOG_LAYER = 12;
     // the keyguard; nothing on top of these can take focus, since they are
     // responsible for power management when displayed.
-    static final int KEYGUARD_LAYER = 15;
-    static final int KEYGUARD_DIALOG_LAYER = 16;
+    static final int KEYGUARD_LAYER = 13;
+    static final int KEYGUARD_DIALOG_LAYER = 14;
+    static final int STATUS_BAR_LAYER = 15;
+    static final int STATUS_BAR_PANEL_LAYER = 16;
     // the navigation bar, if available, shows atop most things
     static final int NAVIGATION_BAR_LAYER = 17;
     // the drag layer: input for drag-and-drop is associated with this window,
@@ -1703,7 +1703,11 @@
                     }
                 }
             }
-            if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr);
+            if (DEBUG_LAYOUT) {
+                Log.i(TAG, "mNavigationBar frame: " + navr);
+                Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
+                            mDockLeft, mDockTop, mDockRight, mDockBottom));
+            }
 
             // apply navigation bar insets
             pf.left = df.left = vf.left = mDockLeft;
@@ -1713,6 +1717,25 @@
 
             mStatusBar.computeFrameLw(pf, df, vf, vf);
 
+            // now, let's consider the navigation bar; if it exists, it must be removed from the
+            // available screen real estate (like an un-hideable status bar)
+            if (navr != null) {
+                if (navr.top == 0) {
+                    // Navigation bar is vertical
+                    if (mRestrictedScreenLeft == navr.left) {
+                        mRestrictedScreenLeft = navr.right;
+                        mRestrictedScreenWidth -= (navr.right - navr.left);
+                    } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
+                        mRestrictedScreenWidth -= (navr.right - navr.left);
+                    }
+                } else {
+                    // Navigation bar horizontal, at bottom
+                    if ((mRestrictedScreenHeight+mRestrictedScreenTop) == navr.bottom) {
+                        mRestrictedScreenHeight -= (navr.bottom-navr.top);
+                    }
+                }
+            }
+
             if (mStatusBar.isVisibleLw()) {
                 // If the status bar is hidden, we don't want to cause
                 // windows behind it to scroll.
@@ -1745,23 +1768,6 @@
                         mRestrictedScreenHeight -= (r.bottom-r.top);
                     }
 
-                    if (navr != null) {
-                        if (navr.top == 0) {
-                            // Navigation bar is vertical
-                            if (mRestrictedScreenLeft == navr.left) {
-                                mRestrictedScreenLeft = navr.right;
-                                mRestrictedScreenWidth -= (navr.right - navr.left);
-                            } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
-                                mRestrictedScreenWidth -= (navr.right - navr.left);
-                            }
-                        } else {
-                            // Navigation bar horizontal, at bottom
-                            if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
-                                mRestrictedScreenHeight -= (navr.bottom-navr.top);
-                            }
-                        }
-                    }
-
                     mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
                     mContentBottom = mCurBottom = mDockBottom
                             = mRestrictedScreenTop + mRestrictedScreenHeight;
@@ -1873,19 +1879,22 @@
                         // permission, so they have the same privileges as the status
                         // bar itself.
                         //
-                        // However, they should still dodge the navigation bar if it exists. A
-                        // straightforward way to do this is to only allow the status bar panels to
-                        // extend to the extrema of the allowable region for the IME dock.
+                        // However, they should still dodge the navigation bar if it exists.
 
                         pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
                         pf.top = df.top = mUnrestrictedScreenTop;
                         pf.right = df.right = hasNavBar
-                                            ? mDockRight
+                                            ? mRestrictedScreenLeft+mRestrictedScreenWidth
                                             : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
                         pf.bottom = df.bottom = hasNavBar
-                                              ? mDockBottom
+                                              ? mRestrictedScreenTop+mRestrictedScreenHeight
                                               : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
 
+                        if (DEBUG_LAYOUT) {
+                            Log.v(TAG, String.format(
+                                        "Laying out status bar window: (%d,%d - %d,%d)",
+                                        pf.left, pf.top, pf.right, pf.bottom));
+                        }
                     } else {
                         pf.left = df.left = mRestrictedScreenLeft;
                         pf.top = df.top = mRestrictedScreenTop;
@@ -1922,12 +1931,23 @@
                     pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
                     pf.top = df.top = cf.top = mUnrestrictedScreenTop;
                     pf.right = df.right = cf.right = hasNavBar
-                                        ? mDockRight
+                                        ? mRestrictedScreenLeft+mRestrictedScreenWidth
                                         : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = cf.bottom = hasNavBar
-                                          ? mDockBottom
+                                          ? mRestrictedScreenTop+mRestrictedScreenHeight
                                           : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
 
+                } else if (attrs.type == TYPE_NAVIGATION_BAR) {
+                    // The navigation bar has Real Ultimate Power.
+                    pf.left = df.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                    if (DEBUG_LAYOUT) {
+                        Log.v(TAG, String.format(
+                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
+                                    pf.left, pf.top, pf.right, pf.bottom));
+                    }
                 } else {
                     pf.left = df.left = cf.left = mRestrictedScreenLeft;
                     pf.top = df.top = cf.top = mRestrictedScreenTop;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 482336b..0323fe0 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2954,7 +2954,7 @@
         mStreamType = streamType;
         // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
         // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
-        mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * audio_bytes_per_sample(format) : sizeof(uint8_t);
+        mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t);
     }
 }
 
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 438883e..a679ca7 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -230,8 +230,14 @@
                         pw.println(':');
                 pw.print("    min=("); pw.print(info.minWidth);
                         pw.print("x"); pw.print(info.minHeight);
+                pw.print(")   minResize=("); pw.print(info.minResizeWidth);
+                        pw.print("x"); pw.print(info.minResizeHeight);
                         pw.print(") updatePeriodMillis=");
                         pw.print(info.updatePeriodMillis);
+                        pw.print(" resizeMode=");
+                        pw.print(info.resizeMode);
+                        pw.print(" autoAdvanceViewId=");
+                        pw.print(info.autoAdvanceViewId);
                         pw.print(" initialLayout=#");
                         pw.print(Integer.toHexString(info.initialLayout));
                         pw.print(" zombie="); pw.println(p.zombie);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 5dd3a6a..ea78b52 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1090,7 +1090,7 @@
         try {
             InetAddress addr = InetAddress.getByAddress(hostAddress);
             LinkProperties lp = tracker.getLinkProperties();
-            return addRoute(lp, RouteInfo.makeHostRoute(addr));
+            return addRouteToAddress(lp, addr);
         } catch (UnknownHostException e) {}
         return false;
     }
@@ -1103,6 +1103,31 @@
         return modifyRoute(p.getInterfaceName(), p, r, 0, false);
     }
 
+    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
+        return modifyRouteToAddress(lp, addr, true);
+    }
+
+    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
+        return modifyRouteToAddress(lp, addr, false);
+    }
+
+    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd) {
+        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
+        if (bestRoute == null) {
+            bestRoute = RouteInfo.makeHostRoute(addr);
+        } else {
+            if (bestRoute.getGateway().equals(addr)) {
+                // if there is no better route, add the implied hostroute for our gateway
+                bestRoute = RouteInfo.makeHostRoute(addr);
+            } else {
+                // if we will connect to this through another route, add a direct route
+                // to it's gateway
+                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
+            }
+        }
+        return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd);
+    }
+
     private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
             boolean doAdd) {
         if ((ifaceName == null) || (lp == null) || (r == null)) return false;
@@ -1713,49 +1738,50 @@
      */
     private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) {
         Collection<RouteInfo> routesToAdd = null;
-        CompareResult<InetAddress> dnsDiff = null;
-
+        CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
+        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
         if (curLp != null) {
             // check for the delta between the current set and the new
-            CompareResult<RouteInfo> routeDiff = curLp.compareRoutes(newLp);
+            routeDiff = curLp.compareRoutes(newLp);
             dnsDiff = curLp.compareDnses(newLp);
-
-            for (RouteInfo r : routeDiff.removed) {
-                if (isLinkDefault || ! r.isDefaultRoute()) {
-                    removeRoute(curLp, r);
-                }
-            }
-            routesToAdd = routeDiff.added;
+        } else if (newLp != null) {
+            routeDiff.added = newLp.getRoutes();
+            dnsDiff.added = newLp.getDnses();
         }
 
-        if (newLp != null) {
-            // if we didn't get a diff from cur -> new, then just use the new
-            if (routesToAdd == null) {
-                routesToAdd = newLp.getRoutes();
+        for (RouteInfo r : routeDiff.removed) {
+            if (isLinkDefault || ! r.isDefaultRoute()) {
+                removeRoute(curLp, r);
             }
+        }
 
-            for (RouteInfo r :  routesToAdd) {
-                if (isLinkDefault || ! r.isDefaultRoute()) {
-                    addRoute(newLp, r);
-                }
+        for (RouteInfo r :  routeDiff.added) {
+            if (isLinkDefault || ! r.isDefaultRoute()) {
+                addRoute(newLp, r);
             }
         }
 
         if (!isLinkDefault) {
             // handle DNS routes
-            Collection<InetAddress> dnsToAdd = null;
-            if (dnsDiff != null) {
-                dnsToAdd = dnsDiff.added;
-                for (InetAddress dnsAddress : dnsDiff.removed) {
-                    removeRoute(curLp, RouteInfo.makeHostRoute(dnsAddress));
+            if (routeDiff.removed.size() == 0 && routeDiff.added.size() == 0) {
+                // no change in routes, check for change in dns themselves
+                for (InetAddress oldDns : dnsDiff.removed) {
+                    removeRouteToAddress(curLp, oldDns);
                 }
-            }
-            if (newLp != null) {
-                if (dnsToAdd == null) {
-                    dnsToAdd = newLp.getDnses();
+                for (InetAddress newDns : dnsDiff.added) {
+                    addRouteToAddress(newLp, newDns);
                 }
-                for(InetAddress dnsAddress : dnsToAdd) {
-                    addRoute(newLp, RouteInfo.makeHostRoute(dnsAddress));
+            } else {
+                // routes changed - remove all old dns entries and add new
+                if (curLp != null) {
+                    for (InetAddress oldDns : curLp.getDnses()) {
+                        removeRouteToAddress(curLp, oldDns);
+                    }
+                }
+                if (newLp != null) {
+                    for (InetAddress newDns : newLp.getDnses()) {
+                        addRouteToAddress(newLp, newDns);
+                    }
                 }
             }
         }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 7399679..d39f565f 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -166,7 +166,7 @@
     private final KeyguardManager mKeyguardManager;
     private final Notification mImeSwitcherNotification;
     private final PendingIntent mImeSwitchPendingIntent;
-    private final boolean mShowOngoingImeSwitcherForPhones;
+    private boolean mShowOngoingImeSwitcherForPhones;
     private boolean mNotificationShown;
 
     class SessionState {
@@ -538,8 +538,8 @@
         mImeSwitcherNotification.vibrate = null;
         Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
         mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
-                com.android.internal.R.bool.show_ongoing_ime_switcher);
+
+        mShowOngoingImeSwitcherForPhones = false;
 
         synchronized (mMethodMap) {
             mFileManager = new InputMethodFileManager(mMethodMap);
@@ -612,6 +612,8 @@
         synchronized (mMethodMap) {
             if (!mSystemReady) {
                 mSystemReady = true;
+                mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
+                        com.android.internal.R.bool.show_ongoing_ime_switcher);
                 try {
                     startInputInnerLocked();
                 } catch (RuntimeException e) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 41e8a31..2366fcb 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -93,6 +93,7 @@
     private static final String KEY_TX = "tx_bytes";
 
     class NetdResponseCode {
+        /* Keep in sync with system/netd/ResponseCode.h */
         public static final int InterfaceListResult       = 110;
         public static final int TetherInterfaceListResult = 111;
         public static final int TetherDnsFwdTgtListResult = 112;
@@ -108,6 +109,7 @@
         public static final int InterfaceTxThrottleResult = 219;
 
         public static final int InterfaceChange           = 600;
+        public static final int BandwidthControl          = 601;
     }
 
     /**
@@ -265,6 +267,20 @@
     }
 
     /**
+     * Notify our observers of a limit reached.
+     */
+    private void notifyLimitReached(String limitName, String iface) {
+        for (INetworkManagementEventObserver obs : mObservers) {
+            try {
+                obs.limitReached(limitName, iface);
+                Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface);
+            } catch (Exception ex) {
+                Slog.w(TAG, "Observer notifier failed", ex);
+            }
+        }
+    }
+
+    /**
      * Let us know the daemon is connected
      */
     protected void onConnected() {
@@ -286,33 +302,52 @@
             }.start();
         }
         public boolean onEvent(int code, String raw, String[] cooked) {
-            if (code == NetdResponseCode.InterfaceChange) {
-                /*
-                 * a network interface change occured
-                 * Format: "NNN Iface added <name>"
-                 *         "NNN Iface removed <name>"
-                 *         "NNN Iface changed <name> <up/down>"
-                 *         "NNN Iface linkstatus <name> <up/down>"
-                 */
-                if (cooked.length < 4 || !cooked[1].equals("Iface")) {
+            switch (code) {
+            case NetdResponseCode.InterfaceChange:
+                    /*
+                     * a network interface change occured
+                     * Format: "NNN Iface added <name>"
+                     *         "NNN Iface removed <name>"
+                     *         "NNN Iface changed <name> <up/down>"
+                     *         "NNN Iface linkstatus <name> <up/down>"
+                     */
+                    if (cooked.length < 4 || !cooked[1].equals("Iface")) {
+                        throw new IllegalStateException(
+                                String.format("Invalid event from daemon (%s)", raw));
+                    }
+                    if (cooked[2].equals("added")) {
+                        notifyInterfaceAdded(cooked[3]);
+                        return true;
+                    } else if (cooked[2].equals("removed")) {
+                        notifyInterfaceRemoved(cooked[3]);
+                        return true;
+                    } else if (cooked[2].equals("changed") && cooked.length == 5) {
+                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
+                        return true;
+                    } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
+                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
+                        return true;
+                    }
                     throw new IllegalStateException(
                             String.format("Invalid event from daemon (%s)", raw));
-                }
-                if (cooked[2].equals("added")) {
-                    notifyInterfaceAdded(cooked[3]);
-                    return true;
-                } else if (cooked[2].equals("removed")) {
-                    notifyInterfaceRemoved(cooked[3]);
-                    return true;
-                } else if (cooked[2].equals("changed") && cooked.length == 5) {
-                    notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
-                    return true;
-                } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
-                    notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
-                    return true;
-                }
-                throw new IllegalStateException(
-                        String.format("Invalid event from daemon (%s)", raw));
+                    // break;
+            case NetdResponseCode.BandwidthControl:
+                    /*
+                     * Bandwidth control needs some attention
+                     * Format: "NNN limit alert <alertName> <ifaceName>"
+                     */
+                    if (cooked.length < 5 || !cooked[1].equals("limit")) {
+                        throw new IllegalStateException(
+                                String.format("Invalid event from daemon (%s)", raw));
+                    }
+                    if (cooked[2].equals("alert")) {
+                        notifyLimitReached(cooked[3], cooked[4]);
+                        return true;
+                    }
+                    throw new IllegalStateException(
+                            String.format("Invalid event from daemon (%s)", raw));
+                    // break;
+            default: break;
             }
             return false;
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8c7e279..76665915 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -230,6 +230,7 @@
         WallpaperManagerService wallpaper = null;
         LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
+        TextServicesManagerService tsms = null;
 
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
             try {
@@ -273,6 +274,14 @@
             }
 
             try {
+                Slog.i(TAG, "Text Service Manager Service");
+                tsms = new TextServicesManagerService(context);
+                ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting Text Service Manager Service", e);
+            }
+
+            try {
                 Slog.i(TAG, "NetworkStats Service");
                 networkStats = new NetworkStatsService(context, networkManagement, alarm);
                 ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
@@ -538,6 +547,7 @@
         final LocationManagerService locationF = location;
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
+        final TextServicesManagerService textServiceManagerServiceF = tsms;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -571,6 +581,7 @@
                 if (countryDetectorF != null) countryDetectorF.systemReady();
                 if (throttleF != null) throttleF.systemReady();
                 if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
+                if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
             }
         });
 
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
new file mode 100644
index 0000000..4a0c837
--- /dev/null
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -0,0 +1,346 @@
+/*
+ * 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.server;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.service.textservice.SpellCheckerService;
+import android.util.Log;
+import android.util.Slog;
+import android.view.textservice.SpellCheckerInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+public class TextServicesManagerService extends ITextServicesManager.Stub {
+    private static final String TAG = TextServicesManagerService.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    private final Context mContext;
+    private boolean mSystemReady;
+    private final TextServicesMonitor mMonitor;
+    private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap =
+            new HashMap<String, SpellCheckerInfo>();
+    private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>();
+    private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups =
+            new HashMap<String, SpellCheckerBindGroup>();
+
+    public void systemReady() {
+        if (!mSystemReady) {
+            mSystemReady = true;
+        }
+    }
+
+    public TextServicesManagerService(Context context) {
+        mSystemReady = false;
+        mContext = context;
+        mMonitor = new TextServicesMonitor();
+        mMonitor.register(context, true);
+        synchronized (mSpellCheckerMap) {
+            buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
+        }
+    }
+
+    private class TextServicesMonitor extends PackageMonitor {
+        @Override
+        public void onSomePackagesChanged() {
+            synchronized (mSpellCheckerMap) {
+                buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap);
+                // TODO: Update for each locale
+                SpellCheckerInfo sci = getCurrentSpellChecker(null);
+                if (sci == null) {
+                    sci = findAvailSpellCheckerLocked(null, null);
+                    if (sci == null) return;
+                    // Set the current spell checker if there is one or more spell checkers
+                    // available. In this case, "sci" is the first one in the available spell
+                    // checkers.
+                    setCurrentSpellChecker(sci);
+                }
+                final String packageName = sci.getPackageName();
+                final int change = isPackageDisappearing(packageName);
+                if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) {
+                    // Package disappearing
+                    setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName));
+                } else if (isPackageModified(packageName)) {
+                    // Package modified
+                    setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName));
+                }
+            }
+        }
+    }
+
+    private static void buildSpellCheckerMapLocked(Context context,
+            ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) {
+        list.clear();
+        map.clear();
+        final PackageManager pm = context.getPackageManager();
+        List<ResolveInfo> services = pm.queryIntentServices(
+                new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+        final int N = services.size();
+        for (int i = 0; i < N; ++i) {
+            final ResolveInfo ri = services.get(i);
+            final ServiceInfo si = ri.serviceInfo;
+            final ComponentName compName = new ComponentName(si.packageName, si.name);
+            if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) {
+                Slog.w(TAG, "Skipping text service " + compName
+                        + ": it does not require the permission "
+                        + android.Manifest.permission.BIND_TEXT_SERVICE);
+                continue;
+            }
+            if (DBG) Slog.d(TAG, "Add: " + compName);
+            final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri);
+            list.add(sci);
+            map.put(sci.getId(), sci);
+        }
+    }
+
+    // TODO: find an appropriate spell checker for specified locale
+    private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) {
+        final int spellCheckersCount = mSpellCheckerList.size();
+        if (spellCheckersCount == 0) {
+            Slog.w(TAG, "no available spell checker services found");
+            return null;
+        }
+        if (prefPackage != null) {
+            for (int i = 0; i < spellCheckersCount; ++i) {
+                final SpellCheckerInfo sci = mSpellCheckerList.get(i);
+                if (prefPackage.equals(sci.getPackageName())) {
+                    return sci;
+                }
+            }
+        }
+        if (spellCheckersCount > 1) {
+            Slog.w(TAG, "more than one spell checker service found, picking first");
+        }
+        return mSpellCheckerList.get(0);
+    }
+
+    // TODO: Save SpellCheckerService by supported languages. Currently only one spell
+    // checker is saved.
+    @Override
+    public SpellCheckerInfo getCurrentSpellChecker(String locale) {
+        synchronized (mSpellCheckerMap) {
+            final String curSpellCheckerId =
+                    Settings.Secure.getString(mContext.getContentResolver(),
+                            Settings.Secure.SPELL_CHECKER_SERVICE);
+            if (TextUtils.isEmpty(curSpellCheckerId)) {
+                return null;
+            }
+            return mSpellCheckerMap.get(curSpellCheckerId);
+        }
+    }
+
+    @Override
+    public void getSpellCheckerService(SpellCheckerInfo info, String locale,
+            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) {
+        if (!mSystemReady) {
+            return;
+        }
+        if (info == null || tsListener == null) {
+            Slog.e(TAG, "getSpellCheckerService: Invalid input.");
+            return;
+        }
+        final String sciId = info.getId();
+        synchronized(mSpellCheckerMap) {
+            if (!mSpellCheckerMap.containsKey(sciId)) {
+                return;
+            }
+            if (mSpellCheckerBindGroups.containsKey(sciId)) {
+                mSpellCheckerBindGroups.get(sciId).addListener(tsListener, locale, scListener);
+                return;
+            }
+            final InternalServiceConnection connection = new InternalServiceConnection(
+                    sciId, locale, scListener);
+            final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
+            serviceIntent.setComponent(info.getComponent());
+            if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+                Slog.e(TAG, "Failed to get a spell checker service.");
+                return;
+            }
+            final SpellCheckerBindGroup group = new SpellCheckerBindGroup(
+                    connection, tsListener, locale, scListener);
+            mSpellCheckerBindGroups.put(sciId, group);
+        }
+        return;
+    }
+
+    @Override
+    public void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
+        synchronized(mSpellCheckerMap) {
+            for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) {
+                if (group == null) continue;
+                group.removeListener(listener);
+            }
+        }
+    }
+
+    private void setCurrentSpellChecker(SpellCheckerInfo sci) {
+        if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return;
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId());
+    }
+
+    // SpellCheckerBindGroup contains active text service session listeners.
+    // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
+    // mSpellCheckerBindGroups
+    private class SpellCheckerBindGroup {
+        final InternalServiceConnection mInternalConnection;
+        final ArrayList<InternalDeathRecipient> mListeners =
+                new ArrayList<InternalDeathRecipient>();
+
+        public SpellCheckerBindGroup(InternalServiceConnection connection,
+                ITextServicesSessionListener listener, String locale,
+                ISpellCheckerSessionListener scListener) {
+            mInternalConnection = connection;
+            addListener(listener, locale, scListener);
+        }
+
+        public void onServiceConnected(ISpellCheckerService spellChecker) {
+            synchronized(mSpellCheckerMap) {
+                for (InternalDeathRecipient listener : mListeners) {
+                    try {
+                        final ISpellCheckerSession session = spellChecker.getISpellCheckerSession(
+                                listener.mScLocale, listener.mScListener);
+                        listener.mTsListener.onServiceConnected(session);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+
+        public void addListener(ITextServicesSessionListener tsListener, String locale,
+                ISpellCheckerSessionListener scListener) {
+            synchronized(mSpellCheckerMap) {
+                try {
+                    final int size = mListeners.size();
+                    for (int i = 0; i < size; ++i) {
+                        if (mListeners.get(i).hasSpellCheckerListener(scListener)) {
+                            // do not add the lister if the group already contains this.
+                            return;
+                        }
+                    }
+                    final InternalDeathRecipient recipient = new InternalDeathRecipient(
+                            this, tsListener, locale, scListener);
+                    scListener.asBinder().linkToDeath(recipient, 0);
+                    mListeners.add(new InternalDeathRecipient(
+                            this, tsListener, locale, scListener));
+                } catch(RemoteException e) {
+                    // do nothing
+                }
+                cleanLocked();
+            }
+        }
+
+        public void removeListener(ISpellCheckerSessionListener listener) {
+            synchronized(mSpellCheckerMap) {
+                final int size = mListeners.size();
+                final ArrayList<InternalDeathRecipient> removeList =
+                        new ArrayList<InternalDeathRecipient>();
+                for (int i = 0; i < size; ++i) {
+                    final InternalDeathRecipient tempRecipient = mListeners.get(i);
+                    if(tempRecipient.hasSpellCheckerListener(listener)) {
+                        removeList.add(tempRecipient);
+                    }
+                }
+                final int removeSize = removeList.size();
+                for (int i = 0; i < removeSize; ++i) {
+                    mListeners.remove(removeList.get(i));
+                }
+                cleanLocked();
+            }
+        }
+
+        private void cleanLocked() {
+            if (mListeners.isEmpty()) {
+                mSpellCheckerBindGroups.remove(this);
+                // Unbind service when there is no active clients.
+                mContext.unbindService(mInternalConnection);
+            }
+        }
+    }
+
+    private class InternalServiceConnection implements ServiceConnection {
+        private final ISpellCheckerSessionListener mListener;
+        private final String mSciId;
+        private final String mLocale;
+        public InternalServiceConnection(
+                String id, String locale, ISpellCheckerSessionListener listener) {
+            mSciId = id;
+            mLocale = locale;
+            mListener = listener;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized(mSpellCheckerMap) {
+                ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
+                final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
+                if (group != null) {
+                    group.onServiceConnected(spellChecker);
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mSpellCheckerBindGroups.remove(mSciId);
+        }
+    }
+
+    private class InternalDeathRecipient implements IBinder.DeathRecipient {
+        public final ITextServicesSessionListener mTsListener;
+        public final ISpellCheckerSessionListener mScListener;
+        public final String mScLocale;
+        private final SpellCheckerBindGroup mGroup;
+        public InternalDeathRecipient(SpellCheckerBindGroup group,
+                ITextServicesSessionListener tsListener, String scLocale,
+                ISpellCheckerSessionListener scListener) {
+            mTsListener = tsListener;
+            mScListener = scListener;
+            mScLocale = scLocale;
+            mGroup = group;
+        }
+
+        public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
+            return mScListener.equals(listener);
+        }
+
+        @Override
+        public void binderDied() {
+            mGroup.removeListener(mScListener);
+        }
+    }
+}
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index b8890aa..cd649ce 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -194,6 +194,7 @@
         }
 
         public void interfaceRemoved(String iface) {}
+        public void limitReached(String limitName, String iface) {}
     }
 
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0924b86..3389f33 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3628,6 +3628,7 @@
         app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
         app.forcingToForeground = null;
         app.foregroundServices = false;
+        app.hasShownUi = false;
         app.debugging = false;
 
         mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
@@ -9218,6 +9219,7 @@
         app.forcingToForeground = null;
         app.foregroundServices = false;
         app.foregroundActivities = false;
+        app.hasShownUi = false;
 
         killServicesLocked(app, true);
 
@@ -9331,8 +9333,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.forcingToForeground = null;
-            app.foregroundServices = false;
             if (mPersistentStartingProcesses.indexOf(app) < 0) {
                 mPersistentStartingProcesses.add(app);
                 restart = true;
@@ -12728,21 +12728,31 @@
             while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
                 ServiceRecord s = jt.next();
                 if (s.startRequested) {
-                    if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
-                        // This service has seen some activity within
-                        // recent memory, so we will keep its process ahead
-                        // of the background processes.
+                    if (app.hasShownUi) {
+                        // If this process has shown some UI, let it immediately
+                        // go to the LRU list because it may be pretty heavy with
+                        // UI stuff.  We'll tag it with a label just to help
+                        // debug and understand what is going on.
                         if (adj > SECONDARY_SERVER_ADJ) {
-                            adj = SECONDARY_SERVER_ADJ;
-                            app.adjType = "started-services";
-                            app.hidden = false;
+                            app.adjType = "started-bg-ui-services";
                         }
-                    }
-                    // If we have let the service slide into the background
-                    // state, still have some text describing what it is doing
-                    // even though the service no longer has an impact.
-                    if (adj > SECONDARY_SERVER_ADJ) {
-                        app.adjType = "started-bg-services";
+                    } else {
+                        if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
+                            // This service has seen some activity within
+                            // recent memory, so we will keep its process ahead
+                            // of the background processes.
+                            if (adj > SECONDARY_SERVER_ADJ) {
+                                adj = SECONDARY_SERVER_ADJ;
+                                app.adjType = "started-services";
+                                app.hidden = false;
+                            }
+                        }
+                        // If we have let the service slide into the background
+                        // state, still have some text describing what it is doing
+                        // even though the service no longer has an impact.
+                        if (adj > SECONDARY_SERVER_ADJ) {
+                            app.adjType = "started-bg-services";
+                        }
                     }
                     // Don't kill this process because it is doing work; it
                     // has said it is doing work.
@@ -13351,15 +13361,15 @@
                                 break;
                         }
                     }
-                } else if (app.curAdj >= PERCEPTIBLE_APP_ADJ) {
-                    if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_INVISIBLE
+                } else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) {
+                    if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_BACKGROUND
                             && app.thread != null) {
                         try {
-                            app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_INVISIBLE);
+                            app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_BACKGROUND);
                         } catch (RemoteException e) {
                         }
                     }
-                    app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_INVISIBLE;
+                    app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
                 } else {
                     app.trimMemoryLevel = 0;
                 }
@@ -13442,7 +13452,7 @@
     }
 
     public boolean profileControl(String process, boolean start,
-            String path, ParcelFileDescriptor fd) throws RemoteException {
+            String path, ParcelFileDescriptor fd, int profileType) throws RemoteException {
 
         try {
             synchronized (this) {
@@ -13487,7 +13497,7 @@
                     }
                 }
             
-                proc.thread.profilerControl(start, path, fd);
+                proc.thread.profilerControl(start, path, fd, profileType);
                 fd = null;
                 return true;
             }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 0d89081..cc58eaf 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -559,6 +559,7 @@
             r.forceNewConfig = false;
             showAskCompatModeDialogLocked(r);
             r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
+            app.hasShownUi = true;
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
                     System.identityHashCode(r),
                     r.info, r.compat, r.icicle, results, newIntents, !andResume,
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 9e597aa..5b59363 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -66,6 +66,7 @@
     boolean setIsForeground;    // Running foreground UI when last set?
     boolean foregroundServices; // Running any services that are foreground?
     boolean foregroundActivities; // Running any activities that are foreground?
+    boolean hasShownUi;         // Has UI been shown in this process since it was started?
     boolean bad;                // True if disabled in the bad process list
     boolean killedBackground;   // True when proc has been killed due to too many bg
     String waitingToKill;       // Process is waiting to be killed when in the bg; reason
@@ -185,6 +186,7 @@
         pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
                 pw.print(" setSchedGroup="); pw.print(setSchedGroup);
                 pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
+                pw.print(" hasShownUi="); pw.println(hasShownUi);
         pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
                 pw.print(" foregroundServices="); pw.print(foregroundServices);
                 pw.print(" forcingToForeground="); pw.println(forcingToForeground);
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index d7d4b03..82bc505 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -288,6 +288,8 @@
         }
     }
 
+    public void limitReached(String limitName, String iface) {}
+
     public int tether(String iface) {
         Log.d(TAG, "Tethering " + iface);
         TetherInterfaceSM sm = null;
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 05e95a7..cf75d6b 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -248,6 +248,8 @@
         }
     }
 
+    public void limitReached(String limitName, String iface) {}
+
     private void showNotification(VpnConfig config, String label, Bitmap icon) {
         NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index c80cd0a..f183f83 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -19,6 +19,7 @@
 import android.app.PendingIntent;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -80,6 +81,7 @@
     private static final int MSG_ENABLE_ADB = 1;
     private static final int MSG_SET_CURRENT_FUNCTION = 2;
     private static final int MSG_SYSTEM_READY = 3;
+    private static final int MSG_BOOT_COMPLETED = 4;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
@@ -87,7 +89,7 @@
     private static final int UPDATE_DELAY = 1000;
 
     private UsbHandler mHandler;
-    private boolean mSystemReady;
+    private boolean mBootCompleted;
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
@@ -141,10 +143,15 @@
                 Process.THREAD_PRIORITY_BACKGROUND);
         thread.start();
         mHandler = new UsbHandler(thread.getLooper());
+
+        if (nativeIsStartRequested()) {
+            if (DEBUG) Slog.d(TAG, "accessory attached at boot");
+            setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
+        }
     }
 
     public void systemReady() {
-        mSystemReady = true;
+        if (DEBUG) Slog.d(TAG, "systemReady");
 
         mNotificationManager = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -236,15 +243,22 @@
         private String mCurrentFunctions;
         private String mDefaultFunctions;
         private UsbAccessory mCurrentAccessory;
-        private boolean mDeferAccessoryAttached;
         private int mUsbNotificationId;
         private boolean mAdbNotificationShown;
 
+        private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                if (DEBUG) Slog.d(TAG, "boot completed");
+                mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
+            }
+        };
+
         private static final int NOTIFICATION_NONE = 0;
         private static final int NOTIFICATION_MTP = 1;
         private static final int NOTIFICATION_PTP = 2;
         private static final int NOTIFICATION_INSTALLER = 3;
-        private static final int NOTIFICATION_ADB = 4;
+        private static final int NOTIFICATION_ACCESSORY = 4;
+        private static final int NOTIFICATION_ADB = 5;
 
         public UsbHandler(Looper looper) {
             super(looper);
@@ -285,6 +299,9 @@
                 // Watch for USB configuration changes
                 mUEventObserver.startObserving(USB_STATE_MATCH);
                 mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+
+                mContext.registerReceiver(mBootCompletedReceiver,
+                        new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
             } catch (Exception e) {
                 Slog.e(TAG, "Error initializing UsbHandler", e);
             }
@@ -406,11 +423,9 @@
                     mCurrentAccessory = new UsbAccessory(strings);
                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
                     // defer accessoryAttached if system is not ready
-                    if (mSystemReady) {
+                    if (mBootCompleted) {
                         mSettingsManager.accessoryAttached(mCurrentAccessory);
-                    } else {
-                        mDeferAccessoryAttached = true;
-                    }
+                    } // else handle in mBootCompletedReceiver
                 } else {
                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
                 }
@@ -421,7 +436,7 @@
                 setEnabledFunctions(mDefaultFunctions);
 
                 if (mCurrentAccessory != null) {
-                    if (mSystemReady) {
+                    if (mBootCompleted) {
                         mSettingsManager.accessoryDetached(mCurrentAccessory);
                     }
                     mCurrentAccessory = null;
@@ -463,7 +478,7 @@
                         // restore defaults when USB is disconnected
                         doSetCurrentFunctions(mDefaultFunctions);
                     }
-                    if (mSystemReady) {
+                    if (mBootCompleted) {
                         updateUsbState();
                     }
                     break;
@@ -497,7 +512,10 @@
                     updateUsbNotification();
                     updateAdbNotification();
                     updateUsbState();
-                    if (mCurrentAccessory != null && mDeferAccessoryAttached) {
+                    break;
+                case MSG_BOOT_COMPLETED:
+                    mBootCompleted = true;
+                    if (mCurrentAccessory != null) {
                         mSettingsManager.accessoryAttached(mCurrentAccessory);
                     }
                     break;
@@ -527,6 +545,10 @@
                     title = r.getText(
                         com.android.internal.R.string.usb_cd_installer_notification_title);
                     id = NOTIFICATION_INSTALLER;
+                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
+                    title = r.getText(
+                        com.android.internal.R.string.usb_accessory_notification_title);
+                    id = NOTIFICATION_ACCESSORY;
                 } else {
                     Slog.e(TAG, "No known USB function in updateUsbNotification");
                 }
@@ -671,4 +693,5 @@
 
     private native String[] nativeGetAccessoryStrings();
     private native ParcelFileDescriptor nativeOpenAccessory();
+    private native boolean nativeIsStartRequested();
 }
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index d8fd7fe..36f5dcb 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -32,10 +32,12 @@
         final int top;
         final Surface surface;
 
-        BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
+        BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b)
                 throws Surface.OutOfResourcesException {
             left = l;
             top = t;
+            int w = r-l;
+            int h = b-t;
             surface = new Surface(session, 0, "BlackSurface",
                     -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
             if (WindowManagerService.SHOW_TRANSACTIONS ||
diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/jni/com_android_server_UsbDeviceManager.cpp
index 6954171..40f0dbd 100644
--- a/services/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/jni/com_android_server_UsbDeviceManager.cpp
@@ -99,11 +99,26 @@
         gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
 }
 
+static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv *env, jobject thiz)
+{
+    int fd = open(DRIVER_NAME, O_RDWR);
+    if (fd < 0) {
+        LOGE("could not open %s", DRIVER_NAME);
+        return false;
+    }
+    int result = ioctl(fd, ACCESSORY_IS_START_REQUESTED);
+    close(fd);
+    return (result == 1);
+}
+
+
 static JNINativeMethod method_table[] = {
     { "nativeGetAccessoryStrings",  "()[Ljava/lang/String;",
                                     (void*)android_server_UsbDeviceManager_getAccessoryStrings },
     { "nativeOpenAccessory",        "()Landroid/os/ParcelFileDescriptor;",
                                     (void*)android_server_UsbDeviceManager_openAccessory },
+    { "nativeIsStartRequested",     "()Z",
+                                    (void*)android_server_UsbDeviceManager_isStartRequested },
 };
 
 int register_android_server_UsbDeviceManager(JNIEnv *env)
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 11f61cc..40659d4 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -60,6 +60,10 @@
 
     sp<Layer> layer(mLayer.promote());
     if (layer != NULL) {
+        uint32_t orientation = layer->getOrientation();
+        if (orientation & Transform::ROT_INVALID) {
+            orientation = 0;
+        }
         *outTransform = layer->getOrientation();
     }
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 40a70a8..a0961ca 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -806,10 +806,10 @@
         mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
     }
 
-    public void notifyDataConnection() {
+    public void notifyDataConnection(String reason) {
         String types[] = getActiveApnTypes();
         for (String apnType : types) {
-            mNotifier.notifyDataConnection(this, null, apnType, getDataConnectionState(apnType));
+            mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 0d551aa..5df2edd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -134,8 +134,6 @@
                 }
             }
 
-            // Not sure if this is needed in CDMALTE phone.
-            // mDataRoaming = regCodeIsRoaming(regState);
             mLteSS.setRadioTechnology(type);
             mLteSS.setState(regCodeToServiceState(regState));
         } else {
@@ -345,13 +343,14 @@
             }
 
             if (cm.getSimState().isSIMReady()) {
-                // SIM is found on the device. If ERI roaming is OFF, use operator name
-                // from CSIM record.
+                // SIM is found on the device. If ERI roaming is OFF and SID/NID matches
+                // one configfured in SIM, use operator name from CSIM record.
                 boolean showSpn =
                     ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
                 int iconIndex = ss.getCdmaEriIconIndex();
 
-                if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF)) {
+                if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
+                    isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) {
                     ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
                 }
             }
@@ -401,7 +400,7 @@
         }
 
         if ((hasCdmaDataConnectionChanged || hasNetworkTypeChanged)) {
-            phone.notifyDataConnection();
+            phone.notifyDataConnection(null);
         }
 
         if (hasRoamingOn) {
@@ -469,6 +468,34 @@
     }
 
     /**
+     * Check whether the specified SID and NID pair appears in the HOME SID/NID list
+     * read from NV or SIM.
+     *
+     * @return true if provided sid/nid pair belongs to operator's home network.
+     */
+    private boolean isInHomeSidNid(int sid, int nid) {
+        // if SID/NID is not available, assume this is home network.
+        if (isSidsAllZeros()) return true;
+
+        // length of SID/NID shold be same
+        if (mHomeSystemId.length != mHomeNetworkId.length) return true;
+
+        if (sid == 0) return true;
+
+        for (int i = 0; i < mHomeSystemId.length; i++) {
+            // Use SID only if NID is a reserved value.
+            // SID 0 and NID 0 and 65535 are reserved. (C.0005 2.6.5.2)
+            if ((mHomeSystemId[i] == sid) &&
+                ((mHomeNetworkId[i] == 0) || (mHomeNetworkId[i] == 65535) ||
+                 (nid == 0) || (nid == 65535) || (mHomeNetworkId[i] == nid))) {
+                return true;
+            }
+        }
+        // SID/NID are not in the list. So device is not in home network
+        return false;
+    }
+
+    /**
      * Returns OTASP_NOT_NEEDED as its not needed for LTE
      */
     @Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 24a468a..2cf4b88 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -130,8 +130,8 @@
     protected String mCurPlmn = null;
 
     protected String mMdn;
-    private int mHomeSystemId[] = null;
-    private int mHomeNetworkId[] = null;
+    protected int mHomeSystemId[] = null;
+    protected int mHomeNetworkId[] = null;
     protected String mMin;
     protected String mPrlVersion;
     protected boolean mIsMinInfoReady = false;
@@ -999,7 +999,7 @@
         }
 
         if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) {
-            phone.notifyDataConnection();
+            phone.notifyDataConnection(null);
         }
 
         if (hasRoamingOn) {
@@ -1481,7 +1481,7 @@
         }
     }
 
-    private boolean isSidsAllZeros() {
+    protected boolean isSidsAllZeros() {
         if (mHomeSystemId != null) {
             for (int i=0; i < mHomeSystemId.length; i++) {
                 if (mHomeSystemId[i] != 0) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 93f4b4e..d3645fa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -915,7 +915,7 @@
         }
 
         if (hasRadioTechnologyChanged) {
-            phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED, Phone.APN_TYPE_ALL);
+            phone.notifyDataConnection(Phone.REASON_NW_TYPE_CHANGED);
         }
 
         if (hasRoamingOn) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
index 1493ab9..13b6129 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
@@ -93,12 +93,9 @@
     }
     
     public void startProfiling(View v) {
-        ViewDebug.startLooperProfiling(new File(Environment.getExternalStorageDirectory(),
-                "looper.trace"));
     }
     
     public void stopProfiling(View v) {
-        ViewDebug.stopLooperProfiling();
     }
 
     @Override
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index e776463..9aa70b0 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -87,8 +87,6 @@
                     mIsProcessing = false;
                 }
 
-                // This is a hack to work around an invalidation bug
-                mBitmapOut.setPixel(0, 0, 0);
                 mOutPixelsAllocation.copyTo(mBitmapOut);
                 mDisplayView.invalidate();
             }
diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml
index 663cc0d..ab61a9e 100644
--- a/tests/TileBenchmark/AndroidManifest.xml
+++ b/tests/TileBenchmark/AndroidManifest.xml
@@ -7,14 +7,16 @@
                  android:label="@string/app_name"
                  android:hardwareAccelerated="true">
         <activity android:name=".ProfileActivity"
-                  android:label="@string/profile_activity">
+                  android:label="@string/profile_activity"
+                  android:theme="@android:style/Theme.Holo.NoActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
         <activity android:name=".PlaybackActivity"
-                  android:label="@string/playback_activity">
+                  android:label="@string/playback_activity"
+                  android:theme="@android:style/Theme.Holo.NoActionBar">
         </activity>
     </application>
 </manifest>
diff --git a/tests/TileBenchmark/res/layout/main.xml b/tests/TileBenchmark/res/layout/main.xml
index 4a81da6..577c466 100644
--- a/tests/TileBenchmark/res/layout/main.xml
+++ b/tests/TileBenchmark/res/layout/main.xml
@@ -23,11 +23,11 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         >
-        <Button
-            android:id="@+id/inspect"
+        <Spinner
+            android:id="@+id/movement"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="@string/inspect_log"
+            android:prompt="@string/movement_method"
             />
         <Spinner
             android:id="@+id/velocity"
@@ -36,6 +36,13 @@
             android:gravity="center_horizontal"
             android:prompt="@string/desired_scroll_velocity"
             />
+        <ToggleButton
+            android:id="@+id/capture"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textOn="@string/capture_stop"
+            android:textOff="@string/capture_start"
+            />
         <EditText
             android:id="@+id/url"
             android:layout_width="0dip"
@@ -44,6 +51,12 @@
             android:imeOptions="actionGo"
             android:layout_weight="1"
             />
+        <Button
+            android:id="@+id/inspect"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/inspect_log"
+            />
     </LinearLayout>
     <com.test.tilebenchmark.ProfiledWebView
         android:id="@+id/web"
diff --git a/tests/TileBenchmark/res/values/colors.xml b/tests/TileBenchmark/res/values/colors.xml
index 3958083..dbb8e72 100644
--- a/tests/TileBenchmark/res/values/colors.xml
+++ b/tests/TileBenchmark/res/values/colors.xml
@@ -18,8 +18,17 @@
     <color name="ready_tile">#ff4ac230</color>
     <!-- The color of tiles with stale / invalid textures -->
     <color name="unready_tile">#ff744400</color>
-    <!-- Background color for logged URLs -->
-    <color name="finished_url">#ff004000</color>
-    <!-- Background color for URLs with logging in progress -->
-    <color name="unfinished_url">#ff400000</color>
+    <!-- Viewport overlay in playback -->
+    <color name="view">#50000050</color>
+    <!-- Invalidated region overlay in playback - start color -->
+    <color name="inval_region_start">#80ff0000</color>
+    <!-- Invalidated region overlay in playback - stop color-->
+    <color name="inval_region_stop">#80ffffff</color>
+
+    <!-- Background color for not testing -->
+    <color name="background_not_testing">#ff000000</color>
+    <!-- Background color for during testing -->
+    <color name="background_start_testing">#ff400000</color>
+    <!-- Background color for testing complete -->
+    <color name="background_stop_testing">#ff004000</color>
 </resources>
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index f70ee2c..66972ac 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -28,6 +28,10 @@
     <string name="loadbutton">Load</string>
     <!-- Button, opens the playback activity [CHAR LIMIT=20] -->
     <string name="inspect_log">Inspect Log</string>
+    <!-- ToggleButton label when pressing starts capture [CHAR LIMIT=15] -->
+    <string name="capture_start">Start Capture</string>
+    <!-- ToggleButton label when pressing stops capture [CHAR LIMIT=15] -->
+    <string name="capture_stop">Stop Capture</string>
     <!-- The speed of auto-scrolling [CHAR LIMIT=30] -->
     <string name="desired_scroll_velocity">Choose Scroll Velocity</string>
     <!-- Pixels moved per frame [CHAR LIMIT=10] -->
@@ -39,6 +43,21 @@
         <item>200</item>
         <item>400</item>
     </string-array>
+    <!-- Drop down menu for selecting scrolling vs manual navigation for
+    capturing [CHAR LIMIT=15] -->
+    <string name="movement_method">Movement Method</string>
+    <!-- Drop down menu entry - automatically scroll to the end of the page
+    with scrollBy() [CHAR LIMIT=15] -->
+    <string name="movement_auto_scroll">Auto-scroll</string>
+    <!-- Drop down menu entry -  [CHAR LIMIT=15] -->
+    <string name="movement_auto_fling">Auto-fling</string>
+    <!-- Drop down menu entry - manually navigate the page(s), hit 'capture'
+    button [CHAR LIMIT=15] -->
+    <string name="movement_manual">Manual</string>
+
+    <!-- Error popup indicating log data couldn't be loaded [CHAR LIMIT=60] -->
+    <string name="error_no_data">Error: log data could not be loaded.</string>
+
     <!-- 25th percentile - 25% of frames fall below this value [CHAR LIMIT=12]
     -->
     <string name="percentile_25">25%ile</string>
@@ -56,7 +75,7 @@
     <string name="format_stat">%4.4f</string>
     <!-- Format string for displaying aggregate stats+values (nr of valid tiles,
     etc.) [CHAR LIMIT=20] -->
-    <string name="format_stat_name">%1$9s %2$3d</string>
+    <string name="format_stat_name">%1$-20s %2$3d</string>
     <!-- Text hovering over canvas, number of tiles ready [CHAR LIMIT=15] -->
     <string name="ready_tiles">Ready Tiles</string>
     <!-- Text hovering over canvas, number tiles not ready [CHAR LIMIT=15] -->
@@ -64,4 +83,7 @@
     <!-- Text hovering over canvas, number of tiles that haven't been
     allocated to a place on the page [CHAR LIMIT=15] -->
     <string name="unplaced_tiles">Unplaced Tiles</string>
+    <!-- Text hovering over canvas, number of invalidated regions this frame
+    [CHAR LIMIT=15] -->
+    <string name="number_invalidates">Invalidates</string>
 </resources>
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
index 5130f5d..36694a7 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
@@ -27,6 +27,7 @@
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -102,7 +103,10 @@
         @Override
         protected void onPostExecute(TileData data[][]) {
             if (data == null) {
-                data = genTestPattern();
+                Toast.makeText(getApplicationContext(),
+                        getResources().getString(R.string.error_no_data),
+                        Toast.LENGTH_LONG).show();
+                return;
             }
             mPlaybackView.setData(data);
 
@@ -166,23 +170,4 @@
 
         new LoadFileTask().execute(ProfileActivity.TEMP_FILENAME);
     }
-
-    private TileData[][] genTestPattern() {
-        final int XMAX = 5;
-        final int FRAMEMAX = 99;
-
-        TileData example[][] = new TileData[FRAMEMAX][];
-        for (int frame = 0; frame < FRAMEMAX; frame++) {
-            int numTiles = frame + 10;
-
-            example[frame] = new TileData[numTiles];
-            for (int t = 0; t < numTiles; t++) {
-                int x = t % XMAX;
-                int y = t / XMAX;
-                boolean isReady = y * 10 < frame;
-                example[frame][t] = new TileData(x, y, isReady, 0);
-            }
-        }
-        return example;
-    }
 }
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index db4a341..35b1563 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -28,19 +28,17 @@
 import java.util.Arrays;
 
 public class PlaybackGraphs {
-    private static final int BAR_WIDTH = PlaybackView.TILEX * 3;
+    private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
     private static final float CANVAS_SCALE = 0.2f;
     private static final double IDEAL_FRAMES = 60;
     private static final int LABELOFFSET = 100;
     private static Paint whiteLabels;
 
-    private static double viewportCoverage(int l, int b, int r, int t,
-            int tileIndexX,
-            int tileIndexY) {
-        if (tileIndexX * PlaybackView.TILEX < r
-                && (tileIndexX + 1) * PlaybackView.TILEX >= l
-                && tileIndexY * PlaybackView.TILEY < t
-                && (tileIndexY + 1) * PlaybackView.TILEY >= b) {
+    private static double viewportCoverage(TileData view, TileData tile) {
+        if (tile.left < view.right
+                && tile.right >= view.left
+                && tile.top < view.bottom
+                && tile.bottom >= view.top) {
             return 1.0f;
         }
         return 0.0f;
@@ -76,13 +74,10 @@
                 // coverage graph
                 @Override
                 public double getValue(TileData[] frame) {
-                    int l = frame[0].x, b = frame[0].y;
-                    int r = frame[1].x, t = frame[1].y;
                     double total = 0, totalCount = 0;
-                    for (int tileID = 2; tileID < frame.length; tileID++) {
+                    for (int tileID = 1; tileID < frame.length; tileID++) {
                         TileData data = frame[tileID];
-                        double coverage = viewportCoverage(l, b, r, t, data.x,
-                                data.y);
+                        double coverage = viewportCoverage(frame[0], data);
                         total += coverage * (data.isReady ? 1 : 0);
                         totalCount += coverage;
                     }
@@ -158,7 +153,7 @@
     public PlaybackGraphs() {
         whiteLabels = new Paint();
         whiteLabels.setColor(Color.WHITE);
-        whiteLabels.setTextSize(PlaybackView.TILEY / 3);
+        whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3);
     }
 
     private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
@@ -177,11 +172,13 @@
             int lastBar = 0;
             for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) {
                 TileData frame[] = tileProfilingData[frameIndex];
-                int newBar = (frame[0].y + frame[1].y) / 2;
+                int newBar = (frame[0].top + frame[0].bottom) / 2;
 
                 MetricGen s = Metrics[metricIndex];
                 double absoluteValue = s.getValue(frame);
                 double relativeValue = absoluteValue / s.getMax();
+                relativeValue = Math.min(1,relativeValue);
+                relativeValue = Math.max(0,relativeValue);
                 int rightPos = (int) (-BAR_WIDTH * metricIndex);
                 int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
 
@@ -207,7 +204,7 @@
             ArrayList<ShapeDrawable> shapes) {
         // Shapes drawn here are drawn relative to the viewRect
         Rect viewRect = shapes.get(shapes.size() - 1).getBounds();
-        canvas.translate(0, 5 * PlaybackView.TILEY - viewRect.top);
+        canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top);
 
         for (ShapeDrawable shape : mShapes) {
             shape.draw(canvas);
@@ -234,13 +231,15 @@
             int yPos = LABELOFFSET;
             canvas.drawText(label, xPos, yPos, whiteLabels);
             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
-                label = resources.getString(R.string.format_stat, mStats[metricIndex][statIndex]);
-                yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILEY / 2;
+                label = resources.getString(R.string.format_stat,
+                        mStats[metricIndex][statIndex]);
+                yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
+                        / 2;
                 canvas.drawText(label, xPos, yPos, whiteLabels);
             }
         }
         for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) {
-            int yPos = LABELOFFSET + stringIndex * PlaybackView.TILEY / 2;
+            int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
             canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels);
         }
     }
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
index f104eac..edc8643 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
@@ -16,6 +16,9 @@
 
 package com.test.tilebenchmark;
 
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -30,8 +33,9 @@
 import java.util.ArrayList;
 
 public class PlaybackView extends View {
-    public static final int TILEX = 300;
-    public static final int TILEY = 300;
+    public static final int TILE_SCALE = 300;
+    private static final int INVAL_FLAG = -2;
+    private static final int INVAL_CYCLE = 250;
 
     private Paint levelPaint = null, coordPaint = null, goldPaint = null;
     private PlaybackGraphs mGraphs;
@@ -39,28 +43,46 @@
     private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>();
     private TileData mProfData[][] = null;
     private GestureDetector mGestureDetector = null;
-    private String mRenderStrings[] = new String[3];
+    private String mRenderStrings[] = new String[4];
 
     private class TileDrawable extends ShapeDrawable {
         TileData tile;
+        String label;
 
-        public TileDrawable(TileData t) {
-            int tileColorId = t.isReady ? R.color.ready_tile
-                    : R.color.unready_tile;
-            getPaint().setColor(getResources().getColor(tileColorId));
-
-            setBounds(t.x * TILEX, t.y * TILEY, (t.x + 1) * TILEX, (t.y + 1)
-                    * TILEY);
+        public TileDrawable(TileData t, int colorId) {
             this.tile = t;
+            getPaint().setColor(getResources().getColor(colorId));
+            if (colorId == R.color.ready_tile
+                    || colorId == R.color.unready_tile) {
+
+                label = (int) (t.left / TILE_SCALE) + ", "
+                        + (int) (t.top / TILE_SCALE);
+                // ignore scale value for tiles
+                setBounds(t.left, t.top,
+                        t.right, t.bottom);
+            } else {
+                setBounds((int) (t.left * t.scale),
+                        (int) (t.top * t.scale),
+                        (int) (t.right * t.scale),
+                        (int) (t.bottom * t.scale));
+            }
+        }
+
+        @SuppressWarnings("unused")
+        public void setColor(int color) {
+            getPaint().setColor(color);
         }
 
         @Override
         public void draw(Canvas canvas) {
             super.draw(canvas);
-            canvas.drawText(Integer.toString(tile.level), getBounds().left,
-                    getBounds().bottom, levelPaint);
-            canvas.drawText(tile.x + "," + tile.y, getBounds().left,
-                    ((getBounds().bottom + getBounds().top) / 2), coordPaint);
+            if (label != null) {
+                canvas.drawText(Integer.toString(tile.level), getBounds().left,
+                        getBounds().bottom, levelPaint);
+                canvas.drawText(label, getBounds().left,
+                        ((getBounds().bottom + getBounds().top) / 2),
+                        coordPaint);
+            }
         }
     }
 
@@ -92,10 +114,10 @@
     private void init() {
         levelPaint = new Paint();
         levelPaint.setColor(Color.WHITE);
-        levelPaint.setTextSize(TILEY / 2);
+        levelPaint.setTextSize(TILE_SCALE / 2);
         coordPaint = new Paint();
         coordPaint.setColor(Color.BLACK);
-        coordPaint.setTextSize(TILEY / 3);
+        coordPaint.setTextSize(TILE_SCALE / 3);
         goldPaint = new Paint();
         goldPaint.setColor(0xffa0e010);
         mGraphs = new PlaybackGraphs();
@@ -110,6 +132,7 @@
         }
 
         mGraphs.draw(canvas, mTempShapes, mRenderStrings, getResources());
+        invalidate(); // may have animations, force redraw
     }
 
     public int setFrame(int frame) {
@@ -117,35 +140,66 @@
             return 0;
         }
 
-        int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0;
+        int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0;
         mTempShapes.clear();
 
-        // draw actual tiles
-        for (int tileID = 2; tileID < mProfData[frame].length; tileID++) {
-            TileData t = mProfData[frame][tileID];
-            mTempShapes.add(new TileDrawable(t));
-            if (t.isReady) {
-                readyTiles++;
+        // create tile shapes (as they're drawn on bottom)
+        for (TileData t : mProfData[frame]) {
+            if (t.level != INVAL_FLAG && t != mProfData[frame][0]) {
+                int colorId;
+                if (t.isReady) {
+                    readyTiles++;
+                    colorId = R.color.ready_tile;
+                } else {
+                    unreadyTiles++;
+                    colorId = R.color.unready_tile;
+                }
+                if (t.left < 0 || t.top < 0) {
+                    unplacedTiles++;
+                }
+                mTempShapes.add(new TileDrawable(t, colorId));
             } else {
-                unreadyTiles++;
-            }
-            if (t.x < 0 || t.y < 0) {
-                unplacedTiles++;
+                numInvals++;
             }
         }
+
+        // create invalidate shapes (drawn above tiles)
+        int invalId = 0;
+        for (TileData t : mProfData[frame]) {
+            if (t.level == INVAL_FLAG && t != mProfData[frame][0]) {
+                TileDrawable invalShape = new TileDrawable(t,
+                        R.color.inval_region_start);
+                ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape,
+                        "color",
+                        getResources().getColor(R.color.inval_region_start),
+                        getResources().getColor(R.color.inval_region_stop));
+                tileAnimator.setDuration(numInvals * INVAL_CYCLE);
+                tileAnimator.setEvaluator(new ArgbEvaluator());
+                tileAnimator.setRepeatCount(ValueAnimator.INFINITE);
+                tileAnimator.setRepeatMode(ValueAnimator.RESTART);
+                float delay = (float) (invalId) * INVAL_CYCLE;
+                tileAnimator.setStartDelay((int) delay);
+                invalId++;
+                tileAnimator.start();
+
+                mTempShapes.add(invalShape);
+            }
+        }
+
         mRenderStrings[0] = getResources().getString(R.string.format_stat_name,
                 getResources().getString(R.string.ready_tiles), readyTiles);
         mRenderStrings[1] = getResources().getString(R.string.format_stat_name,
                 getResources().getString(R.string.unready_tiles), unreadyTiles);
         mRenderStrings[2] = getResources().getString(R.string.format_stat_name,
-                getResources().getString(R.string.unplaced_tiles), unplacedTiles);
+                getResources().getString(R.string.unplaced_tiles),
+                unplacedTiles);
+        mRenderStrings[3] = getResources().getString(R.string.format_stat_name,
+                getResources().getString(R.string.number_invalidates),
+                numInvals);
 
-        // draw view rect (using first two TileData objects)
-        ShapeDrawable viewShape = new ShapeDrawable();
-        viewShape.getPaint().setColor(0xff0000ff);
-        viewShape.setAlpha(64);
-        viewShape.setBounds(mProfData[frame][0].x, mProfData[frame][0].y,
-                mProfData[frame][1].x, mProfData[frame][1].y);
+        // draw view rect (using first TileData object, on top)
+        TileDrawable viewShape = new TileDrawable(mProfData[frame][0],
+                R.color.view);
         mTempShapes.add(viewShape);
         this.invalidate();
         return frame;
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index 23b6275..1521807 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -38,6 +38,7 @@
 import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
+import android.widget.ToggleButton;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -58,11 +59,24 @@
                                                      // before test
 
     Button mInspectButton;
+    ToggleButton mCaptureButton;
     Spinner mVelocitySpinner;
+    Spinner mMovementSpinner;
     EditText mUrl;
     ProfiledWebView mWeb;
     ProfileCallback mCallback;
 
+    LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient();
+    AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient();
+
+    private enum TestingState {
+        NOT_TESTING,
+        PRE_TESTING,
+        START_TESTING,
+        STOP_TESTING,
+        SAVED_TESTING
+    };
+
     private class VelocitySelectedListener implements OnItemSelectedListener {
         @Override
         public void onItemSelected(AdapterView<?> parent, View view,
@@ -77,6 +91,31 @@
         }
     }
 
+    private class MovementSelectedListener implements OnItemSelectedListener {
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view,
+                int position, long id) {
+            String movementStr = parent.getItemAtPosition(position).toString();
+            if (movementStr == getResources().getString(
+                    R.string.movement_auto_scroll)
+                    || movementStr == getResources().getString(
+                            R.string.movement_auto_fling)) {
+                mWeb.setWebViewClient(mAutoLoggingWebViewClient);
+                mCaptureButton.setEnabled(false);
+                mVelocitySpinner.setEnabled(true);
+            } else if (movementStr == getResources().getString(
+                    R.string.movement_manual)) {
+                mWeb.setWebViewClient(mLoggingWebViewClient);
+                mCaptureButton.setEnabled(true);
+                mVelocitySpinner.setEnabled(false);
+            }
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+        }
+    }
+
     private class LoggingWebViewClient extends WebViewClient {
         @Override
         public boolean shouldOverrideUrlLoading(WebView view, String url) {
@@ -88,6 +127,9 @@
             super.onPageStarted(view, url, favicon);
             mUrl.setText(url);
         }
+    }
+
+    private class AutoLoggingWebViewClient extends LoggingWebViewClient {
 
         @Override
         public void onPageFinished(WebView view, String url) {
@@ -100,10 +142,16 @@
 
                 @Override
                 public void onFinish() {
-                    mWeb.startScrollTest(mCallback);
+                    startViewProfiling(true);
                 }
             }.start();
         }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            setTestingState(TestingState.PRE_TESTING);
+        }
     }
 
     private class StoreFileTask extends
@@ -125,24 +173,65 @@
 
         @Override
         protected void onPostExecute(Void v) {
-            mUrl.setBackgroundResource(R.color.finished_url);
+            setTestingState(TestingState.SAVED_TESTING);
         }
     }
 
+    public void setTestingState(TestingState state) {
+        switch (state) {
+            case NOT_TESTING:
+                mUrl.setBackgroundResource(R.color.background_not_testing);
+                mInspectButton.setEnabled(true);
+                mMovementSpinner.setEnabled(true);
+                break;
+            case PRE_TESTING:
+                mInspectButton.setEnabled(false);
+                mMovementSpinner.setEnabled(false);
+                break;
+            case START_TESTING:
+                mUrl.setBackgroundResource(R.color.background_start_testing);
+                mInspectButton.setEnabled(false);
+                mMovementSpinner.setEnabled(false);
+                break;
+            case STOP_TESTING:
+                mUrl.setBackgroundResource(R.color.background_stop_testing);
+                break;
+            case SAVED_TESTING:
+                mInspectButton.setEnabled(true);
+                mMovementSpinner.setEnabled(true);
+                break;
+        }
+    }
+
+    /** auto - automatically scroll. */
+    private void startViewProfiling(boolean auto) {
+        if (!auto) {
+            // manual, toggle capture button to indicate capture state to user
+            mCaptureButton.setChecked(true);
+        }
+        mWeb.startScrollTest(mCallback, auto);
+        setTestingState(TestingState.START_TESTING);
+    }
+
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         mInspectButton = (Button) findViewById(R.id.inspect);
+        mCaptureButton = (ToggleButton) findViewById(R.id.capture);
         mVelocitySpinner = (Spinner) findViewById(R.id.velocity);
+        mMovementSpinner = (Spinner) findViewById(R.id.movement);
         mUrl = (EditText) findViewById(R.id.url);
         mWeb = (ProfiledWebView) findViewById(R.id.web);
         mCallback = new ProfileCallback() {
             @SuppressWarnings("unchecked")
             @Override
             public void profileCallback(TileData[][] data) {
-                new StoreFileTask().execute(new Pair<String, TileData[][]>(TEMP_FILENAME, data));
+                new StoreFileTask().execute(new Pair<String, TileData[][]>(
+                        TEMP_FILENAME, data));
+                mCaptureButton.setChecked(false);
+                setTestingState(TestingState.STOP_TESTING);
             }
         };
 
@@ -166,6 +255,33 @@
                 new VelocitySelectedListener());
         mVelocitySpinner.setSelection(3);
 
+        // Movement spinner
+        String content[] = {
+                getResources().getString(R.string.movement_auto_scroll),
+                getResources().getString(R.string.movement_auto_fling),
+                getResources().getString(R.string.movement_manual)
+        };
+        adapter = new ArrayAdapter<CharSequence>(this,
+                android.R.layout.simple_spinner_item, content);
+        adapter.setDropDownViewResource(
+                android.R.layout.simple_spinner_dropdown_item);
+        mMovementSpinner.setAdapter(adapter);
+        mMovementSpinner.setOnItemSelectedListener(
+                new MovementSelectedListener());
+        mMovementSpinner.setSelection(0);
+
+        // Capture toggle button
+        mCaptureButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mCaptureButton.isChecked()) {
+                    startViewProfiling(false);
+                } else {
+                    mWeb.stopScrollTest();
+                }
+            }
+        });
+
         // Custom profiling WebView
         WebSettings settings = mWeb.getSettings();
         settings.setJavaScriptEnabled(true);
@@ -180,12 +296,13 @@
             public boolean onEditorAction(TextView v, int actionId,
                     KeyEvent event) {
                 String url = mUrl.getText().toString();
-                mUrl.setBackgroundResource(R.color.unfinished_url);
                 mWeb.loadUrl(url);
                 mWeb.requestFocus();
                 return true;
             }
         });
+
+        setTestingState(TestingState.NOT_TESTING);
     }
 
     public void setCallback(ProfileCallback callback) {
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index 6560624..d3941be 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -59,12 +59,13 @@
     }
 
     /*
-     * Called once the page is loaded to start scrolling for evaluating tiles
+     * Called once the page is loaded to start scrolling for evaluating tiles.
+     * If autoScrolling isn't set, stop must be called manually.
      */
-    public void startScrollTest(ProfileCallback callback) {
-        isScrolling = true;
+    public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
+        isScrolling = autoScrolling;
         mCallback = callback;
-        super.tileProfilingStart();
+        tileProfilingStart();
         invalidate();
     }
 
@@ -72,19 +73,31 @@
      * Called once the page has stopped scrolling
      */
     public void stopScrollTest() {
-        float testRatio = super.tileProfilingStop();
+        super.tileProfilingStop();
+
+        if (mCallback == null) {
+            tileProfilingClear();
+            return;
+        }
 
         TileData data[][] = new TileData[super.tileProfilingNumFrames()][];
         for (int frame = 0; frame < data.length; frame++) {
             data[frame] = new TileData[
-                    super.tileProfilingNumTilesInFrame(frame)];
+                    tileProfilingNumTilesInFrame(frame)];
             for (int tile = 0; tile < data[frame].length; tile++) {
-                int x = super.tileProfilingGetX(frame, tile);
-                int y = super.tileProfilingGetY(frame, tile);
-                boolean isReady = super.tileProfilingGetReady(frame, tile);
-                int level = super.tileProfilingGetLevel(frame, tile);
+                int left = tileProfilingGetInt(frame, tile, "left");
+                int top = tileProfilingGetInt(frame, tile, "top");
+                int right = tileProfilingGetInt(frame, tile, "right");
+                int bottom = tileProfilingGetInt(frame, tile, "bottom");
 
-                data[frame][tile] = new TileData(x, y, isReady, level);
+                boolean isReady = super.tileProfilingGetInt(
+                        frame, tile, "isReady") == 1;
+                int level = tileProfilingGetInt(frame, tile, "level");
+
+                float scale = tileProfilingGetFloat(frame, tile, "scale");
+
+                data[frame][tile] = new TileData(left, top, right, bottom,
+                        isReady, level, scale);
             }
         }
         super.tileProfilingClear();
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
index 7d4bb9f..3e729a6 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
@@ -19,14 +19,24 @@
 import java.io.Serializable;
 
 public class TileData implements Serializable {
-    public int x, y;
+    int left, top, right, bottom;
     public boolean isReady;
     public int level;
+    public float scale;
 
-    public TileData(int x, int y, boolean isReady, int level) {
-        this.x = x;
-        this.y = y;
+    public TileData(int left, int top, int right, int bottom, boolean isReady,
+            int level, float scale) {
+        this.left = left;
+        this.right = right;
+        this.top = top;
+        this.bottom = bottom;
         this.isReady = isReady;
         this.level = level;
+        this.scale = scale;
+    }
+
+    public String toString() {
+        return "Tile (" + left + "," + top + ")->("
+                + right + "," + bottom + ")";
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index b09e04b..fa7cf21 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -68,7 +68,7 @@
 public class WifiWatchdogStateMachine extends StateMachine {
 
 
-    private static final boolean VDBG = true;  //TODO : Remove this before merge
+    private static final boolean VDBG = false;
     private static final boolean DBG = true;
     private static final String WWSM_TAG = "WifiWatchdogStateMachine";