Merge "Added the KeySetManager."
diff --git a/api/current.txt b/api/current.txt
index 424472c..56962b9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20082,6 +20082,14 @@
     method public void setPriority(android.renderscript.RenderScript.Priority);
   }
 
+  public static final class RenderScript.ContextType extends java.lang.Enum {
+    method public static android.renderscript.RenderScript.ContextType valueOf(java.lang.String);
+    method public static final android.renderscript.RenderScript.ContextType[] values();
+    enum_constant public static final android.renderscript.RenderScript.ContextType DEBUG;
+    enum_constant public static final android.renderscript.RenderScript.ContextType NORMAL;
+    enum_constant public static final android.renderscript.RenderScript.ContextType PROFILE;
+  }
+
   public static final class RenderScript.Priority extends java.lang.Enum {
     method public static android.renderscript.RenderScript.Priority valueOf(java.lang.String);
     method public static final android.renderscript.RenderScript.Priority[] values();
@@ -26290,6 +26298,10 @@
     field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
     field public static final deprecated int MEMORY_TYPE_NORMAL = 0; // 0x0
     field public static final deprecated int MEMORY_TYPE_PUSH_BUFFERS = 3; // 0x3
+    field public static final int ROTATION_ANIMATION_CHANGED = 4096; // 0x1000
+    field public static final int ROTATION_ANIMATION_CROSSFADE = 1; // 0x1
+    field public static final int ROTATION_ANIMATION_JUMPCUT = 2; // 0x2
+    field public static final int ROTATION_ANIMATION_ROTATE = 0; // 0x0
     field public static final int SCREEN_BRIGHTNESS_CHANGED = 2048; // 0x800
     field public static final int SCREEN_ORIENTATION_CHANGED = 1024; // 0x400
     field public static final int SOFT_INPUT_ADJUST_NOTHING = 48; // 0x30
@@ -26340,6 +26352,7 @@
     field public float horizontalWeight;
     field public deprecated int memoryType;
     field public java.lang.String packageName;
+    field public int rotationAnimation;
     field public float screenBrightness;
     field public int screenOrientation;
     field public int softInputMode;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4a0ee48..ebca041 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -448,7 +448,7 @@
      * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
      * @hide
      */
-    private static class Action implements Parcelable {
+    public static class Action implements Parcelable {
         public int icon;
         public CharSequence title;
         public PendingIntent actionIntent;
@@ -500,7 +500,10 @@
         };
     }
 
-    private Action[] actions;
+    /**
+     * @hide
+     */
+    public Action[] actions;
 
     /**
      * Constructs a Notification object with default values.
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index b678df7..44aa06f 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -24,6 +24,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -227,7 +228,6 @@
         String libDir = (appInfo.nativeLibraryDir != null)
                 ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
                 : null;
-        String externalFilesDir = getExternalFilesDir(null).getCanonicalPath();
 
         // Filters, the scan queue, and the set of resulting entities
         HashSet<String> filterSet = new HashSet<String>();
@@ -259,8 +259,17 @@
         // getExternalFilesDir() location associated with this app.  Technically there should
         // not be any files here if the app does not properly have permission to access
         // external storage, but edge cases happen. fullBackupFileTree() catches
-        // IOExceptions and similar, and treats them as non-fatal, so we rely on that here.
-        fullBackupFileTree(packageName, FullBackup.MANAGED_EXTERNAL_TREE_TOKEN, externalFilesDir, null, data);
+        // IOExceptions and similar, and treats them as non-fatal, so we rely on that; and
+        // we know a priori that processes running as the system UID are not permitted to
+        // access external storage, so we check for that as well to avoid nastygrams in
+        // the log.
+        if (Process.myUid() != Process.SYSTEM_UID) {
+            File efLocation = getExternalFilesDir(null);
+            if (efLocation != null) {
+                fullBackupFileTree(packageName, FullBackup.MANAGED_EXTERNAL_TREE_TOKEN,
+                        efLocation.getCanonicalPath(), null, data);
+            }
+        }
     }
 
     /**
@@ -281,7 +290,7 @@
         String spDir;
         String cacheDir;
         String libDir;
-        String efDir;
+        String efDir = null;
         String filePath;
 
         ApplicationInfo appInfo = getApplicationInfo();
@@ -295,7 +304,14 @@
             libDir = (appInfo.nativeLibraryDir == null)
                     ? null
                     : new File(appInfo.nativeLibraryDir).getCanonicalPath();
-            efDir = getExternalFilesDir(null).getCanonicalPath();
+
+            // may or may not have external files access to attempt backup/restore there
+            if (Process.myUid() != Process.SYSTEM_UID) {
+                File efLocation = getExternalFilesDir(null);
+                if (efLocation != null) {
+                    efDir = efLocation.getCanonicalPath();
+                }
+            }
 
             // Now figure out which well-defined tree the file is placed in, working from
             // most to least specific.  We also specifically exclude the lib and cache dirs.
@@ -324,7 +340,7 @@
         } else if (filePath.startsWith(mainDir)) {
             domain = FullBackup.ROOT_TREE_TOKEN;
             rootpath = mainDir;
-        } else if (filePath.startsWith(efDir)) {
+        } else if ((efDir != null) && filePath.startsWith(efDir)) {
             domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
             rootpath = efDir;
         } else {
@@ -451,7 +467,13 @@
         } else if (domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
             basePath = getCacheDir().getCanonicalPath();
         } else if (domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
-            basePath = getExternalFilesDir(null).getCanonicalPath();
+            // make sure we can try to restore here before proceeding
+            if (Process.myUid() != Process.SYSTEM_UID) {
+                File efLocation = getExternalFilesDir(null);
+                if (efLocation != null) {
+                    basePath = getExternalFilesDir(null).getCanonicalPath();
+                }
+            }
         } else {
             // Not a supported location
             Log.i(TAG, "Data restored from non-app domain " + domain + ", ignoring");
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index fa3bf4d..a470e70 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -31,6 +31,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.TypedValue;
 import android.widget.RemoteViews;
 import android.widget.RemoteViews.OnClickHandler;
@@ -55,38 +56,39 @@
 
     Context mContext;
     String mPackageName;
+    Handler mHandler;
+    int mHostId;
+    Callbacks mCallbacks = new Callbacks();
+    final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
+    private OnClickHandler mOnClickHandler;
 
     class Callbacks extends IAppWidgetHost.Stub {
-        public void updateAppWidget(int appWidgetId, RemoteViews views) {
+        public void updateAppWidget(int appWidgetId, RemoteViews views, int userId) {
             if (isLocalBinder() && views != null) {
                 views = views.clone();
-                views.setUser(mUser);
+                views.setUser(new UserHandle(userId));
             }
-            Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
-            msg.arg1 = appWidgetId;
-            msg.obj = views;
+            Message msg = mHandler.obtainMessage(HANDLE_UPDATE, appWidgetId, userId, views);
             msg.sendToTarget();
         }
 
-        public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+        public void providerChanged(int appWidgetId, AppWidgetProviderInfo info, int userId) {
             if (isLocalBinder() && info != null) {
                 info = info.clone();
             }
-            Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
-            msg.arg1 = appWidgetId;
-            msg.obj = info;
+            Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED,
+                    appWidgetId, userId, info);
             msg.sendToTarget();
         }
 
-        public void providersChanged() {
-            Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED);
+        public void providersChanged(int userId) {
+            Message msg = mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED, userId, 0);
             msg.sendToTarget();
         }
 
-        public void viewDataChanged(int appWidgetId, int viewId) {
-            Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED);
-            msg.arg1 = appWidgetId;
-            msg.arg2 = viewId;
+        public void viewDataChanged(int appWidgetId, int viewId, int userId) {
+            Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED,
+                    appWidgetId, viewId, userId);
             msg.sendToTarget();
         }
     }
@@ -99,7 +101,7 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case HANDLE_UPDATE: {
-                    updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
+                    updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj, msg.arg2);
                     break;
                 }
                 case HANDLE_PROVIDER_CHANGED: {
@@ -107,26 +109,17 @@
                     break;
                 }
                 case HANDLE_PROVIDERS_CHANGED: {
-                    onProvidersChanged();
+                    onProvidersChanged(msg.arg1);
                     break;
                 }
                 case HANDLE_VIEW_DATA_CHANGED: {
-                    viewDataChanged(msg.arg1, msg.arg2);
+                    viewDataChanged(msg.arg1, msg.arg2, (Integer) msg.obj);
                     break;
                 }
             }
         }
     }
 
-    Handler mHandler;
-
-    int mHostId;
-    Callbacks mCallbacks = new Callbacks();
-    final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
-    private OnClickHandler mOnClickHandler;
-    // Optionally set by lockscreen
-    private UserHandle mUser;
-
     public AppWidgetHost(Context context, int hostId) {
         this(context, hostId, null, context.getMainLooper());
     }
@@ -140,14 +133,9 @@
         mOnClickHandler = handler;
         mHandler = new UpdateHandler(looper);
         mDisplayMetrics = context.getResources().getDisplayMetrics();
-        mUser = Process.myUserHandle();
         bindService();
     }
 
-    /** @hide */
-    public void setUserId(int userId) {
-        mUser = new UserHandle(userId);
-    }
 
     private static void bindService() {
         synchronized (sServiceLock) {
@@ -163,23 +151,15 @@
      * becomes visible, i.e. from onStart() in your Activity.
      */
     public void startListening() {
-        startListeningAsUser(UserHandle.myUserId());
-    }
-
-    /**
-     * Start receiving onAppWidgetChanged calls for your AppWidgets.  Call this when your activity
-     * becomes visible, i.e. from onStart() in your Activity.
-     * @hide
-     */
-    public void startListeningAsUser(int userId) {
         int[] updatedIds;
         ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
 
+        final int userId = mContext.getUserId();
         try {
             if (mPackageName == null) {
                 mPackageName = mContext.getPackageName();
             }
-            updatedIds = sService.startListeningAsUser(
+            updatedIds = sService.startListening(
                     mCallbacks, mPackageName, mHostId, updatedViews, userId);
         }
         catch (RemoteException e) {
@@ -191,7 +171,7 @@
             if (updatedViews.get(i) != null) {
                 updatedViews.get(i).setUser(new UserHandle(userId));
             }
-            updateAppWidgetView(updatedIds[i], updatedViews.get(i));
+            updateAppWidgetView(updatedIds[i], updatedViews.get(i), userId);
         }
     }
 
@@ -201,26 +181,14 @@
      */
     public void stopListening() {
         try {
-            sService.stopListeningAsUser(mHostId, UserHandle.myUserId());
+            sService.stopListening(mHostId, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
-    }
 
-    /**
-     * Stop receiving onAppWidgetChanged calls for your AppWidgets.  Call this when your activity is
-     * no longer visible, i.e. from onStop() in your Activity.
-     * @hide
-     */
-    public void stopListeningAsUser(int userId) {
-        try {
-            sService.stopListeningAsUser(mHostId, userId);
-        }
-        catch (RemoteException e) {
-            throw new RuntimeException("system server dead?", e);
-        }
-        // Also clear the views
+        // This is here because keyguard needs it since it'll be switching users after this call.
+        // If it turns out other apps need to call this often, we should re-think how this works.
         clearViews();
     }
 
@@ -230,11 +198,12 @@
      * @return a appWidgetId
      */
     public int allocateAppWidgetId() {
+
         try {
             if (mPackageName == null) {
                 mPackageName = mContext.getPackageName();
             }
-            return sService.allocateAppWidgetId(mPackageName, mHostId);
+            return sService.allocateAppWidgetId(mPackageName, mHostId, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -247,7 +216,7 @@
      * @return a appWidgetId
      * @hide
      */
-    public static int allocateAppWidgetIdForSystem(int hostId) {
+    public static int allocateAppWidgetIdForSystem(int hostId, int userId) {
         checkCallerIsSystem();
         try {
             if (sService == null) {
@@ -256,7 +225,7 @@
             Context systemContext =
                     (Context) ActivityThread.currentActivityThread().getSystemContext();
             String packageName = systemContext.getPackageName();
-            return sService.allocateAppWidgetId(packageName, hostId);
+            return sService.allocateAppWidgetId(packageName, hostId, userId);
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
@@ -272,7 +241,7 @@
             if (sService == null) {
                 bindService();
             }
-            return sService.getAppWidgetIdsForHost(mHostId);
+            return sService.getAppWidgetIdsForHost(mHostId, mContext.getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
@@ -297,7 +266,7 @@
         synchronized (mViews) {
             mViews.remove(appWidgetId);
             try {
-                sService.deleteAppWidgetId(appWidgetId);
+                sService.deleteAppWidgetId(appWidgetId, mContext.getUserId());
             }
             catch (RemoteException e) {
                 throw new RuntimeException("system server dead?", e);
@@ -309,13 +278,13 @@
      * Stop listening to changes for this AppWidget.
      * @hide
      */
-    public static void deleteAppWidgetIdForSystem(int appWidgetId) {
+    public static void deleteAppWidgetIdForSystem(int appWidgetId, int userId) {
         checkCallerIsSystem();
         try {
             if (sService == null) {
                 bindService();
             }
-            sService.deleteAppWidgetId(appWidgetId);
+            sService.deleteAppWidgetId(appWidgetId, userId);
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
@@ -331,7 +300,7 @@
      */
     public void deleteHost() {
         try {
-            sService.deleteHost(mHostId);
+            sService.deleteHost(mHostId, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -347,8 +316,16 @@
      * </ul>
      */
     public static void deleteAllHosts() {
+        deleteAllHosts(UserHandle.myUserId());
+    }
+
+    /**
+     * Private method containing a userId
+     * @hide
+     */
+    public static void deleteAllHosts(int userId) {
         try {
-            sService.deleteAllHosts();
+            sService.deleteAllHosts(userId);
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -361,8 +338,9 @@
      */
     public final AppWidgetHostView createView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
+        final int userId = context.getUserId();
         AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
-        view.setUserId(mUser.getIdentifier());
+        view.setUserId(userId);
         view.setOnClickHandler(mOnClickHandler);
         view.setAppWidget(appWidgetId, appWidget);
         synchronized (mViews) {
@@ -370,9 +348,9 @@
         }
         RemoteViews views;
         try {
-            views = sService.getAppWidgetViews(appWidgetId);
+            views = sService.getAppWidgetViews(appWidgetId, userId);
             if (views != null) {
-                views.setUser(mUser);
+                views.setUser(new UserHandle(mContext.getUserId()));
             }
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -422,10 +400,20 @@
      * are added, updated or removed, or widget components are enabled or disabled.)
      */
     protected void onProvidersChanged() {
-        // Do nothing
+        onProvidersChanged(mContext.getUserId());
     }
 
-    void updateAppWidgetView(int appWidgetId, RemoteViews views) {
+    /**
+     * Private method containing a userId
+     * @hide
+     */
+    protected void onProvidersChanged(int userId) {
+        checkUserMatch(userId);
+        // Does nothing
+    }
+
+    void updateAppWidgetView(int appWidgetId, RemoteViews views, int userId) {
+        checkUserMatch(userId);
         AppWidgetHostView v;
         synchronized (mViews) {
             v = mViews.get(appWidgetId);
@@ -435,7 +423,8 @@
         }
     }
 
-    void viewDataChanged(int appWidgetId, int viewId) {
+    void viewDataChanged(int appWidgetId, int viewId, int userId) {
+        checkUserMatch(userId);
         AppWidgetHostView v;
         synchronized (mViews) {
             v = mViews.get(appWidgetId);
@@ -445,6 +434,16 @@
         }
     }
 
+    // Ensure that the userId passed to us agrees with the one associated with this instance
+    // of AppWidgetHost.
+    // TODO: This should be removed in production code.
+    private void checkUserMatch(int userId) {
+        if (userId != mContext.getUserId()) {
+            throw new IllegalStateException(
+                "User ids don't match, userId=" + userId + ", mUserId=" + mContext.getUserId());
+        }
+    }
+
     /**
      * Clear the list of Views that have been created by this AppWidgetHost.
      */
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6b1c3e2..e68d23a 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -16,6 +16,7 @@
 
 package android.appwidget;
 
+import android.app.ActivityManagerNative;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -268,8 +269,8 @@
     /**
      * Sent when the custom extras for an AppWidget change.
      *
-     * @see AppWidgetProvider#onAppWidgetOptionsChanged 
-     *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context, 
+     * @see AppWidgetProvider#onAppWidgetOptionsChanged
+     *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
      *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
      */
     public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
@@ -352,7 +353,7 @@
      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
      * and outside of the handler.
      * This method will only work when called from the uid that owns the AppWidget provider.
-     * 
+     *
      * <p>
      * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
      * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
@@ -362,7 +363,7 @@
      */
     public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
         try {
-            sService.updateAppWidgetIds(appWidgetIds, views);
+            sService.updateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -382,7 +383,7 @@
      */
     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
         try {
-            sService.updateAppWidgetOptions(appWidgetId, options);
+            sService.updateAppWidgetOptions(appWidgetId, options, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -402,7 +403,7 @@
      */
     public Bundle getAppWidgetOptions(int appWidgetId) {
         try {
-            return sService.getAppWidgetOptions(appWidgetId);
+            return sService.getAppWidgetOptions(appWidgetId, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -436,7 +437,7 @@
      * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
      *
      * This update  differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
-     * RemoteViews object which is passed is understood to be an incomplete representation of the 
+     * RemoteViews object which is passed is understood to be an incomplete representation of the
      * widget, and hence does not replace the cached representation of the widget. As of API
      * level 17, the new properties set within the views objects will be appended to the cached
      * representation of the widget, and hence will persist.
@@ -458,7 +459,7 @@
      */
     public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
         try {
-            sService.partiallyUpdateAppWidgetIds(appWidgetIds, views);
+            sService.partiallyUpdateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
@@ -507,7 +508,7 @@
      */
     public void updateAppWidget(ComponentName provider, RemoteViews views) {
         try {
-            sService.updateAppWidgetProvider(provider, views);
+            sService.updateAppWidgetProvider(provider, views, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -523,7 +524,7 @@
      */
     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
         try {
-            sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
+            sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -557,7 +558,8 @@
      */
     public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
         try {
-            List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter);
+            List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter,
+                    mContext.getUserId());
             for (AppWidgetProviderInfo info : providers) {
                 // Converting complex to dp.
                 info.minWidth =
@@ -584,7 +586,8 @@
      */
     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
         try {
-            AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
+            AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId,
+                    mContext.getUserId());
             if (info != null) {
                 // Converting complex to dp.
                 info.minWidth =
@@ -617,7 +620,7 @@
      */
     public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
         try {
-            sService.bindAppWidgetId(appWidgetId, provider, null);
+            sService.bindAppWidgetId(appWidgetId, provider, null, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -641,7 +644,7 @@
      */
     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
         try {
-            sService.bindAppWidgetId(appWidgetId, provider, options);
+            sService.bindAppWidgetId(appWidgetId, provider, options, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -667,7 +670,7 @@
         }
         try {
             return sService.bindAppWidgetIdIfAllowed(
-                    mContext.getPackageName(), appWidgetId, provider, null);
+                    mContext.getPackageName(), appWidgetId, provider, null, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -696,8 +699,8 @@
             return false;
         }
         try {
-            return sService.bindAppWidgetIdIfAllowed(
-                    mContext.getPackageName(), appWidgetId, provider, options);
+            return sService.bindAppWidgetIdIfAllowed(mContext.getPackageName(), appWidgetId,
+                    provider, options, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -715,7 +718,7 @@
      */
     public boolean hasBindAppWidgetPermission(String packageName) {
         try {
-            return sService.hasBindAppWidgetPermission(packageName);
+            return sService.hasBindAppWidgetPermission(packageName, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -733,7 +736,7 @@
      */
     public void setBindAppWidgetPermission(String packageName, boolean permission) {
         try {
-            sService.setBindAppWidgetPermission(packageName, permission);
+            sService.setBindAppWidgetPermission(packageName, permission, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
@@ -794,7 +797,7 @@
      */
     public int[] getAppWidgetIds(ComponentName provider) {
         try {
-            return sService.getAppWidgetIds(provider);
+            return sService.getAppWidgetIds(provider, mContext.getUserId());
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c964af4..8a9eed2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2691,6 +2691,14 @@
             throws PackageManager.NameNotFoundException;
 
     /**
+     * Get the userId associated with this context
+     * @return user id
+     *
+     * @hide
+     */
+    public abstract int getUserId();
+
+    /**
      * Return a new Context object for the current Context but whose resources
      * are adjusted to match the given Configuration.  Each call to this method
      * returns a new instance of a Context object; Context objects are not
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 736dd99..2f1bf8c 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -623,6 +623,12 @@
         return mBase.createPackageContextAsUser(packageName, flags, user);
     }
 
+    /** @hide */
+    @Override
+    public int getUserId() {
+        return mBase.getUserId();
+    }
+
     @Override
     public Context createConfigurationContext(Configuration overrideConfiguration) {
         return mBase.createConfigurationContext(overrideConfiguration);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 000c56c..3a04c27 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -62,7 +62,7 @@
      * NetworkInfo for the new network is also passed as an extra. This lets
      * any receivers of the broadcast know that they should not necessarily
      * tell the user that no data traffic will be possible. Instead, the
-     * reciever should expect another broadcast soon, indicating either that
+     * receiver should expect another broadcast soon, indicating either that
      * the failover attempt succeeded (and so there is still overall data
      * connectivity), or that the failover attempt failed, meaning that all
      * connectivity has been lost.
@@ -70,6 +70,7 @@
      * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY
      * is set to {@code true} if there are no connected networks at all.
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
 
     /**
@@ -78,6 +79,7 @@
      *
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String CONNECTIVITY_ACTION_IMMEDIATE =
             "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE";
 
@@ -149,8 +151,8 @@
     /**
      * Broadcast action to indicate the change of data activity status
      * (idle or active) on a network in a recent period.
-     * The network becomes active when data transimission is started, or
-     * idle if there is no data transimition for a period of time.
+     * The network becomes active when data transmission is started, or
+     * idle if there is no data transmission for a period of time.
      * {@hide}
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -198,32 +200,42 @@
      * the network and it's condition.
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String INET_CONDITION_ACTION =
             "android.net.conn.INET_CONDITION_ACTION";
 
     /**
-     * Broadcast Action: A tetherable connection has come or gone
-     * TODO - finish the doc
+     * Broadcast Action: A tetherable connection has come or gone.
+     * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER},
+     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and
+     * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate
+     * the current state of tethering.  Each include a list of
+     * interface names in that state (may be empty).
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_TETHER_STATE_CHANGED =
             "android.net.conn.TETHER_STATE_CHANGED";
 
     /**
      * @hide
-     * gives a String[]
+     * gives a String[] listing all the interfaces configured for
+     * tethering and currently available for tethering.
      */
     public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
 
     /**
      * @hide
-     * gives a String[]
+     * gives a String[] listing all the interfaces currently tethered
+     * (ie, has dhcp support and packets potentially forwarded/NATed)
      */
     public static final String EXTRA_ACTIVE_TETHER = "activeArray";
 
     /**
      * @hide
-     * gives a String[]
+     * gives a String[] listing all the interfaces we tried to tether and
+     * failed.  Use {@link #getLastTetherError} to find the error code
+     * for any interfaces listed here.
      */
     public static final String EXTRA_ERRORED_TETHER = "erroredArray";
 
@@ -233,6 +245,7 @@
      * notification.
      * @hide
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED =
             "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED";
     /**
@@ -243,61 +256,63 @@
     public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal";
 
     /**
-     * The absence of APN..
+     * The absence of a connection type.
      * @hide
      */
     public static final int TYPE_NONE        = -1;
 
     /**
-     * The Default Mobile data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The Mobile data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route)
      */
     public static final int TYPE_MOBILE      = 0;
     /**
-     * The Default WIFI data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The WIFI data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_WIFI        = 1;
     /**
-     * An MMS-specific Mobile data connection.  This connection may be the
-     * same as {@link #TYPE_MOBILE} but it may be different.  This is used
-     * by applications needing to talk to the carrier's Multimedia Messaging
-     * Service servers.  It may coexist with default data connections.
+     * An MMS-specific Mobile data connection.  This network type may use the
+     * same network interface as {@link #TYPE_MOBILE} or it may use a different
+     * one.  This is used by applications needing to talk to the carrier's
+     * Multimedia Messaging Service servers.
      */
     public static final int TYPE_MOBILE_MMS  = 2;
     /**
-     * A SUPL-specific Mobile data connection.  This connection may be the
-     * same as {@link #TYPE_MOBILE} but it may be different.  This is used
-     * by applications needing to talk to the carrier's Secure User Plane
-     * Location servers for help locating the device.  It may coexist with
-     * default data connections.
+     * A SUPL-specific Mobile data connection.  This network type may use the
+     * same network interface as {@link #TYPE_MOBILE} or it may use a different
+     * one.  This is used by applications needing to talk to the carrier's
+     * Secure User Plane Location servers for help locating the device.
      */
     public static final int TYPE_MOBILE_SUPL = 3;
     /**
-     * A DUN-specific Mobile data connection.  This connection may be the
-     * same as {@link #TYPE_MOBILE} but it may be different.  This is used
-     * by applicaitons performing a Dial Up Networking bridge so that
-     * the carrier is aware of DUN traffic.  It may coexist with default data
-     * connections.
+     * A DUN-specific Mobile data connection.  This network type may use the
+     * same network interface as {@link #TYPE_MOBILE} or it may use a different
+     * one.  This is sometimes by the system when setting up an upstream connection
+     * for tethering so that the carrier is aware of DUN traffic.
      */
     public static final int TYPE_MOBILE_DUN  = 4;
     /**
-     * A High Priority Mobile data connection.  This connection is typically
-     * the same as {@link #TYPE_MOBILE} but the routing setup is different.
-     * Only requesting processes will have access to the Mobile DNS servers
-     * and only IP's explicitly requested via {@link #requestRouteToHost}
-     * will route over this interface if a default route exists.
+     * A High Priority Mobile data connection.  This network type uses the
+     * same network interface as {@link #TYPE_MOBILE} but the routing setup
+     * is different.  Only requesting processes will have access to the
+     * Mobile DNS servers and only IP's explicitly requested via {@link #requestRouteToHost}
+     * will route over this interface if no default route exists.
      */
     public static final int TYPE_MOBILE_HIPRI = 5;
     /**
-     * The Default WiMAX data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The WiMAX data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_WIMAX       = 6;
 
     /**
-     * The Default Bluetooth data connection. When active, all data traffic
-     * will use this connection by default.
+     * The Bluetooth data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_BLUETOOTH   = 7;
 
@@ -307,25 +322,26 @@
     public static final int TYPE_DUMMY       = 8;
 
     /**
-     * The Default Ethernet data connection.  When active, all data traffic
-     * will use this connection by default.
+     * The Ethernet data connection.  When active, all data traffic
+     * will use this network type's interface by default
+     * (it has a default route).
      */
     public static final int TYPE_ETHERNET    = 9;
 
     /**
-     * Over the air Adminstration.
+     * Over the air Administration.
      * {@hide}
      */
     public static final int TYPE_MOBILE_FOTA = 10;
 
     /**
-     * IP Multimedia Subsystem
+     * IP Multimedia Subsystem.
      * {@hide}
      */
     public static final int TYPE_MOBILE_IMS  = 11;
 
     /**
-     * Carrier Branded Services
+     * Carrier Branded Services.
      * {@hide}
      */
     public static final int TYPE_MOBILE_CBS  = 12;
@@ -349,7 +365,7 @@
      *
      * @deprecated Since we support so many more networks now, the single
      *             network default network preference can't really express
-     *             the heirarchy.  Instead, the default is defined by the
+     *             the hierarchy.  Instead, the default is defined by the
      *             networkAttributes in config.xml.  You can determine
      *             the current value by calling {@link #getNetworkPreference()}
      *             from an App.
@@ -359,7 +375,11 @@
 
     /**
      * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in
-     * milliseconds.
+     * milliseconds.  This was introduced because IPv6 routes seem to take a
+     * moment to settle - trying network activity before the routes are adjusted
+     * can lead to packets using the wrong interface or having the wrong IP address.
+     * This delay is a bit crude, but in the future hopefully we will have kernel
+     * notifications letting us know when it's safe to use the new network.
      *
      * @hide
      */
@@ -367,11 +387,23 @@
 
     private final IConnectivityManager mService;
 
+    /**
+     * Tests if a given integer represents a valid network type.
+     * @param networkType the type to be tested
+     * @return a boolean.  {@code true} if the type is valid, else {@code false}
+     */
     public static boolean isNetworkTypeValid(int networkType) {
         return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
     }
 
-    /** {@hide} */
+    /**
+     * Returns a non-localized string representing a given network type.
+     * ONLY used for debugging output.
+     * @param type the type needing naming
+     * @return a String for the given type, or a string version of the type ("87")
+     * if no name is known.
+     * {@hide}
+     */
     public static String getNetworkTypeName(int type) {
         switch (type) {
             case TYPE_MOBILE:
@@ -407,7 +439,13 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Checks if a given type uses the cellular data connection.
+     * This should be replaced in the future by a network property.
+     * @param networkType the type to check
+     * @return a boolean - {@code true} if uses cellular network, else {@code false}
+     * {@hide}
+     */
     public static boolean isNetworkTypeMobile(int networkType) {
         switch (networkType) {
             case TYPE_MOBILE:
@@ -424,6 +462,17 @@
         }
     }
 
+    /**
+     * Specifies the preferred network type.  When the device has more
+     * than one type available the preferred network type will be used.
+     * Note that this made sense when we only had 2 network types,
+     * but with more and more default networks we need an array to list
+     * their ordering.  This will be deprecated soon.
+     *
+     * @param preference the network type to prefer over all others.  It is
+     *         unspecified what happens to the old preferred network in the
+     *         overall ordering.
+     */
     public void setNetworkPreference(int preference) {
         try {
             mService.setNetworkPreference(preference);
@@ -431,6 +480,17 @@
         }
     }
 
+    /**
+     * Retrieves the current preferred network type.
+     * Note that this made sense when we only had 2 network types,
+     * but with more and more default networks we need an array to list
+     * their ordering.  This will be deprecated soon.
+     *
+     * @return an integer representing the preferred network type
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
     public int getNetworkPreference() {
         try {
             return mService.getNetworkPreference();
@@ -440,11 +500,16 @@
     }
 
     /**
-     * Returns details about the currently active data network. When connected,
-     * this network is the default route for outgoing connections. You should
-     * always check {@link NetworkInfo#isConnected()} before initiating network
-     * traffic. This may return {@code null} when no networks are available.
-     * <p>This method requires the caller to hold the permission
+     * Returns details about the currently active default data network. When
+     * connected, this network is the default route for outgoing connections.
+     * You should always check {@link NetworkInfo#isConnected()} before initiating
+     * network traffic. This may return {@code null} when there is no default
+     * network.
+     *
+     * @return a {@link NetworkInfo} object for the current default network
+     *        or {@code null} if no network default network is currently active
+     *
+     * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public NetworkInfo getActiveNetworkInfo() {
@@ -455,7 +520,19 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Returns details about the currently active default data network
+     * for a given uid.  This is for internal use only to avoid spying
+     * other apps.
+     *
+     * @return a {@link NetworkInfo} object for the current default network
+     *        for the given uid or {@code null} if no default network is
+     *        available for the specified uid.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
+     * {@hide}
+     */
     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
         try {
             return mService.getActiveNetworkInfoForUid(uid);
@@ -464,6 +541,19 @@
         }
     }
 
+    /**
+     * Returns connection status information about a particular
+     * network type.
+     *
+     * @param networkType integer specifying which networkType in
+     *        which you're interested.
+     * @return a {@link NetworkInfo} object for the requested
+     *        network type or {@code null} if the type is not
+     *        supported by the device.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
     public NetworkInfo getNetworkInfo(int networkType) {
         try {
             return mService.getNetworkInfo(networkType);
@@ -472,6 +562,16 @@
         }
     }
 
+    /**
+     * Returns connection status information about all network
+     * types supported by the device.
+     *
+     * @return an array of {@link NetworkInfo} objects.  Check each
+     * {@link NetworkInfo#getType} for which type each applies.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
     public NetworkInfo[] getAllNetworkInfo() {
         try {
             return mService.getAllNetworkInfo();
@@ -480,7 +580,17 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Returns the IP information for the current default network.
+     *
+     * @return a {@link LinkProperties} object describing the IP info
+     *        for the current default network, or {@code null} if there
+     *        is no current default network.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     * {@hide}
+     */
     public LinkProperties getActiveLinkProperties() {
         try {
             return mService.getActiveLinkProperties();
@@ -489,7 +599,18 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Returns the IP information for a given network type.
+     *
+     * @param networkType the network type of interest.
+     * @return a {@link LinkProperties} object describing the IP info
+     *        for the given networkType, or {@code null} if there is
+     *        no current default network.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     * {@hide}
+     */
     public LinkProperties getLinkProperties(int networkType) {
         try {
             return mService.getLinkProperties(networkType);
@@ -498,7 +619,18 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Tells each network type to set its radio power state as directed.
+     *
+     * @param turnOn a boolean, {@code true} to turn the radios on,
+     *        {@code false} to turn them off.
+     * @return a boolean, {@code true} indicating success.  All network types
+     *        will be tried, even if some fail.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+     * {@hide}
+     */
     public boolean setRadios(boolean turnOn) {
         try {
             return mService.setRadios(turnOn);
@@ -507,7 +639,18 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * Tells a given networkType to set its radio power state as directed.
+     *
+     * @param networkType the int networkType of interest.
+     * @param turnOn a boolean, {@code true} to turn the radio on,
+     *        {@code} false to turn it off.
+     * @return a boolean, {@code true} indicating success.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+     * {@hide}
+     */
     public boolean setRadio(int networkType, boolean turnOn) {
         try {
             return mService.setRadio(networkType, turnOn);
@@ -642,6 +785,9 @@
      * network is active. Quota status can change rapidly, so these values
      * shouldn't be cached.
      *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
      * @hide
      */
     public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
@@ -656,6 +802,9 @@
      * Gets the value of the setting for enabling Mobile data.
      *
      * @return Whether mobile data is enabled.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
     public boolean getMobileDataEnabled() {
@@ -669,8 +818,8 @@
     /**
      * Sets the persisted value for enabling/disabling Mobile data.
      *
-     * @param enabled Whether the mobile data connection should be
-     *            used or not.
+     * @param enabled Whether the user wants the mobile data connection used
+     *            or not.
      * @hide
      */
     public void setMobileDataEnabled(boolean enabled) {
@@ -693,6 +842,13 @@
     }
 
     /**
+     * Get the set of tetherable, available interfaces.  This list is limited by
+     * device configuration and current interface existence.
+     *
+     * @return an array of 0 or more Strings of tetherable interface names.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableIfaces() {
@@ -704,6 +860,12 @@
     }
 
     /**
+     * Get the set of tethered interfaces.
+     *
+     * @return an array of 0 or more String of currently tethered interface names.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetheredIfaces() {
@@ -715,6 +877,18 @@
     }
 
     /**
+     * Get the set of interface names which attempted to tether but
+     * failed.  Re-attempting to tether may cause them to reset to the Tethered
+     * state.  Alternatively, causing the interface to be destroyed and recreated
+     * may cause them to reset to the available state.
+     * {@link ConnectivityManager#getLastTetherError} can be used to get more
+     * information on the cause of the errors.
+     *
+     * @return an array of 0 or more String indicating the interface names
+     *        which failed to tether.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetheringErroredIfaces() {
@@ -726,7 +900,19 @@
     }
 
     /**
-     * @return error A TETHER_ERROR value indicating success or failure type
+     * Attempt to tether the named interface.  This will setup a dhcp server
+     * on the interface, forward and NAT IP packets and forward DNS requests
+     * to the best active upstream network interface.  Note that if no upstream
+     * IP network interface is available, dhcp will still run and traffic will be
+     * allowed between the tethered devices and this device, though upstream net
+     * access will of course fail until an upstream network interface becomes
+     * active.
+     *
+     * @param iface the interface name to tether.
+     * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int tether(String iface) {
@@ -738,7 +924,13 @@
     }
 
     /**
-     * @return error A TETHER_ERROR value indicating success or failure type
+     * Stop tethering the named interface.
+     *
+     * @param iface the interface name to untether.
+     * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int untether(String iface) {
@@ -750,6 +942,14 @@
     }
 
     /**
+     * Check if the device allows for tethering.  It may be disabled via
+     * {@code ro.tether.denied} system property, {@link Settings#TETHER_SUPPORTED} or
+     * due to device configuration.
+     *
+     * @return a boolean - {@code true} indicating Tethering is supported.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public boolean isTetheringSupported() {
@@ -761,6 +961,15 @@
     }
 
     /**
+     * Get the list of regular expressions that define any tetherable
+     * USB network interfaces.  If USB tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * @return an array of 0 or more regular expression Strings defining
+     *        what interfaces are considered tetherable usb interfaces.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableUsbRegexs() {
@@ -772,6 +981,15 @@
     }
 
     /**
+     * Get the list of regular expressions that define any tetherable
+     * Wifi network interfaces.  If Wifi tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * @return an array of 0 or more regular expression Strings defining
+     *        what interfaces are considered tetherable wifi interfaces.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableWifiRegexs() {
@@ -783,6 +1001,15 @@
     }
 
     /**
+     * Get the list of regular expressions that define any tetherable
+     * Bluetooth network interfaces.  If Bluetooth tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * @return an array of 0 or more regular expression Strings defining
+     *        what interfaces are considered tetherable bluetooth interfaces.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public String[] getTetherableBluetoothRegexs() {
@@ -794,6 +1021,17 @@
     }
 
     /**
+     * Attempt to both alter the mode of USB and Tethering of USB.  A
+     * utility method to deal with some of the complexity of USB - will
+     * attempt to switch to Rndis and subsequently tether the resulting
+     * interface on {@code true} or turn off tethering and switch off
+     * Rndis on {@code false}.
+     *
+     * @param enable a boolean - {@code true} to enable tethering
+     * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public int setUsbTethering(boolean enable) {
@@ -828,9 +1066,15 @@
     public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
 
     /**
-     * @param iface The name of the interface we're interested in
+     * Get a more detailed error code after a Tethering or Untethering
+     * request asynchronously failed.
+     *
+     * @param iface The name of the interface of interest
      * @return error The error code of the last error tethering or untethering the named
      *               interface
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public int getLastTetherError(String iface) {
@@ -842,9 +1086,16 @@
     }
 
     /**
-     * Ensure the device stays awake until we connect with the next network
-     * @param forWhome The name of the network going down for logging purposes
+     * Try to ensure the device stays awake until we connect with the next network.
+     * Actually just holds a wakelock for a number of seconds while we try to connect
+     * to any default networks.  This will expire if the timeout passes or if we connect
+     * to a default after this is called.  For internal use only.
+     *
+     * @param forWhom the name of the network going down for logging purposes
      * @return {@code true} on success, {@code false} on failure
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public boolean requestNetworkTransitionWakelock(String forWhom) {
@@ -857,8 +1108,14 @@
     }
 
     /**
+     * Report network connectivity status.  This is currently used only
+     * to alter status bar UI.
+     *
      * @param networkType The type of network you want to report on
      * @param percentage The quality of the connection 0 is bad, 100 is good
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#STATUS_BAR}.
      * {@hide}
      */
     public void reportInetCondition(int networkType, int percentage) {
@@ -869,7 +1126,16 @@
     }
 
     /**
-     * @param proxyProperties The definition for the new global http proxy
+     * Set a network-independent global http proxy.  This is not normally what you want
+     * for typical HTTP proxies - they are general network dependent.  However if you're
+     * doing something unusual like general internal filtering this may be useful.  On
+     * a private network where the proxy is not accessible, you may break HTTP using this.
+     *
+     * @param proxyProperties The a {@link ProxyProperites} object defining the new global
+     *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
     public void setGlobalProxy(ProxyProperties p) {
@@ -880,7 +1146,13 @@
     }
 
     /**
-     * @return proxyProperties for the current global proxy
+     * Retrieve any network-independent global HTTP proxy.
+     *
+     * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null}
+     *        if no global HTTP proxy is set.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public ProxyProperties getGlobalProxy() {
@@ -892,7 +1164,14 @@
     }
 
     /**
-     * @return proxyProperties for the current proxy (global if set, network specific if not)
+     * Get the HTTP proxy settings for the current default network.  Note that
+     * if a global proxy is set, it will override any per-network setting.
+     *
+     * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no
+     *        HTTP proxy is active.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
     public ProxyProperties getProxy() {
@@ -904,8 +1183,15 @@
     }
 
     /**
+     * Sets a secondary requirement bit for the given networkType.
+     * This requirement bit is generally under the control of the carrier
+     * or its agents and is not directly controlled by the user.
+     *
      * @param networkType The network who's dependence has changed
-     * @param met Boolean - true if network use is ok, false if not
+     * @param met Boolean - true if network use is OK, false if not
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public void setDataDependency(int networkType, boolean met) {
@@ -919,11 +1205,15 @@
      * Returns true if the hardware supports the given network type
      * else it returns false.  This doesn't indicate we have coverage
      * or are authorized onto a network, just whether or not the
-     * hardware supports it.  For example a gsm phone without a sim
-     * should still return true for mobile data, but a wifi only tablet
-     * would return false.
-     * @param networkType The nework type we'd like to check
-     * @return true if supported, else false
+     * hardware supports it.  For example a GSM phone without a SIM
+     * should still return {@code true} for mobile data, but a wifi only
+     * tablet would return {@code false}.
+     *
+     * @param networkType The network type we'd like to check
+     * @return {@code true} if supported, else {@code false}
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
     public boolean isNetworkSupported(int networkType) {
@@ -936,9 +1226,16 @@
     /**
      * Returns if the currently active data network is metered. A network is
      * classified as metered when the user is sensitive to heavy data usage on
-     * that connection. You should check this before doing large data transfers,
-     * and warn the user or delay the operation until another network is
-     * available.
+     * that connection due to monetary costs, data limitations or
+     * battery/performance issues. You should check this before doing large
+     * data transfers, and warn the user or delay the operation until another
+     * network is available.
+     *
+     * @return {@code true} if large transfers should be avoided, otherwise
+     *        {@code false}.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public boolean isActiveNetworkMetered() {
         try {
@@ -948,7 +1245,15 @@
         }
     }
 
-    /** {@hide} */
+    /**
+     * If the LockdownVpn mechanism is enabled, updates the vpn
+     * with a reload of its profile.
+     *
+     * @return a boolean with {@code} indicating success
+     *
+     * <p>This method can only be called by the system UID
+     * {@hide}
+     */
     public boolean updateLockdownVpn() {
         try {
             return mService.updateLockdownVpn();
@@ -958,6 +1263,14 @@
     }
 
     /**
+     * Signal that the captive portal check on the indicated network
+     * is complete and we can turn the network on for general use.
+     *
+     * @param info the {@link NetworkInfo} object for the networkType
+     *        in question.
+     *
+     * <p>This method requires the call to hold the permission
+     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
     public void captivePortalCheckComplete(NetworkInfo info) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 9dc77b9..71d8fb6 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -153,6 +153,7 @@
         int mCurWindowPrivateFlags = mWindowPrivateFlags;
         final Rect mVisibleInsets = new Rect();
         final Rect mWinFrame = new Rect();
+        final Rect mOverscanInsets = new Rect();
         final Rect mContentInsets = new Rect();
         final Configuration mConfiguration = new Configuration();
         
@@ -252,7 +253,7 @@
 
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
-            public void resized(Rect frame, Rect contentInsets,
+            public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                     Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0);
@@ -627,7 +628,7 @@
 
                     final int relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
-                            View.VISIBLE, 0, mWinFrame, mContentInsets,
+                            View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
                             mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 152827d..9522112 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -169,10 +169,10 @@
      * </ul>
      */
     public static final Pattern PHONE
-        = Pattern.compile(                                  // sdd = space, dot, or dash
-                "(\\+[0-9]+[\\- \\.]*)?"                    // +<digits><sdd>*
-                + "(\\([0-9]+\\)[\\- \\.]*)?"               // (<digits>)<sdd>*
-                + "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit> 
+        = Pattern.compile(                      // sdd = space, dot, or dash
+                "(\\+[0-9]+[\\- \\.]*)?"        // +<digits><sdd>*
+                + "(\\([0-9]+\\)[\\- \\.]*)?"   // (<digits>)<sdd>*
+                + "([0-9][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit>
 
     /**
      *  Convenience method to take all of the non-null matching groups in a
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 7ff8d09..6c48e43 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -497,22 +497,22 @@
 
     @Override
     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
-        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
+        return nQuickReject(mRenderer, left, top, right, bottom);
     }
     
     private static native boolean nQuickReject(int renderer, float left, float top,
-            float right, float bottom, int edge);
+            float right, float bottom);
 
     @Override
     public boolean quickReject(Path path, EdgeType type) {
         path.computeBounds(mPathBounds, true);
         return nQuickReject(mRenderer, mPathBounds.left, mPathBounds.top,
-                mPathBounds.right, mPathBounds.bottom, type.nativeInt);
+                mPathBounds.right, mPathBounds.bottom);
     }
 
     @Override
     public boolean quickReject(RectF rect, EdgeType type) {
-        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom, type.nativeInt);
+        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom);
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 15bd46c..8ec07ef 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -45,7 +45,7 @@
      */
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
-    void resized(in Rect frame, in Rect contentInsets,
+    void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
             in Rect visibleInsets, boolean reportDraw, in Configuration newConfig);
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index ff9dcce..0a8e609 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -63,6 +63,9 @@
      * {@link WindowManagerGlobal#RELAYOUT_DEFER_SURFACE_DESTROY}.
      * @param outFrame Rect in which is placed the new position/size on
      * screen.
+     * @param outOverscanInsets Rect in which is placed the offsets from
+     * <var>outFrame</var> in which the content of the window are inside
+     * of the display's overlay region.
      * @param outContentInsets Rect in which is placed the offsets from
      * <var>outFrame</var> in which the content of the window should be
      * placed.  This can be used to modify the window layout to ensure its
@@ -84,7 +87,7 @@
      */
     int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
-            int flags, out Rect outFrame,
+            int flags, out Rect outFrame, out Rect outOverscanInsets,
             out Rect outContentInsets, out Rect outVisibleInsets,
             out Configuration outConfig, out Surface outSurface);
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index de64e14..03a9b09 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -75,7 +75,6 @@
 
     private int mGenerationId; // incremented each time mNativeSurface changes
     private final Canvas mCanvas = new CompatibleCanvas();
-    private int mCanvasSaveCount; // Canvas save count at time of lockCanvas()
 
     // The Translator for density compatibility mode.  This is used for scaling
     // the canvas to perform the appropriate density transformation.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 9f50065..7ef7e2b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -339,11 +339,6 @@
         nativeSetLayer(mNativeObject, zorder);
     }
 
-    public void setPosition(int x, int y) {
-        checkNotReleased();
-        nativeSetPosition(mNativeObject, (float)x, (float)y);
-    }
-
     public void setPosition(float x, float y) {
         checkNotReleased();
         nativeSetPosition(mNativeObject, x, y);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9008521..5d0f523 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -103,6 +103,7 @@
     MyWindow mWindow;
     final Rect mVisibleInsets = new Rect();
     final Rect mWinFrame = new Rect();
+    final Rect mOverscanInsets = new Rect();
     final Rect mContentInsets = new Rect();
     final Configuration mConfiguration = new Configuration();
     
@@ -507,7 +508,7 @@
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                             visible ? VISIBLE : GONE,
                             WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
-                            mWinFrame, mContentInsets,
+                            mWinFrame, mOverscanInsets, mContentInsets,
                             mVisibleInsets, mConfiguration, mNewSurface);
                     if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                         mReportDrawNeeded = true;
@@ -642,7 +643,7 @@
         }
 
         @Override
-        public void resized(Rect frame, Rect contentInsets,
+        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dcf51e4..ab8f934 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5679,20 +5679,45 @@
         if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
             mUserPaddingStart = UNDEFINED_PADDING;
             mUserPaddingEnd = UNDEFINED_PADDING;
-            if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
-                    || mAttachInfo == null
-                    || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
-                internalSetPadding(insets.left, insets.top, insets.right, insets.bottom);
-                return true;
-            } else {
-                internalSetPadding(0, 0, 0, 0);
-                return false;
+            Rect localInsets = sThreadLocal.get();
+            if (localInsets == null) {
+                localInsets = new Rect();
+                sThreadLocal.set(localInsets);
             }
+            boolean res = computeFitSystemWindows(insets, localInsets);
+            internalSetPadding(localInsets.left, localInsets.top,
+                    localInsets.right, localInsets.bottom);
+            return res;
         }
         return false;
     }
 
     /**
+     * @hide Compute the insets that should be consumed by this view and the ones
+     * that should propagate to those under it.
+     */
+    protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) {
+        if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
+                || mAttachInfo == null
+                || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
+                        && !mAttachInfo.mOverscanRequested)) {
+            outLocalInsets.set(inoutInsets);
+            inoutInsets.set(0, 0, 0, 0);
+            return true;
+        } else {
+            // The application wants to take care of fitting system window for
+            // the content...  however we still need to take care of any overscan here.
+            final Rect overscan = mAttachInfo.mOverscanInsets;
+            outLocalInsets.set(overscan);
+            inoutInsets.left -= overscan.left;
+            inoutInsets.top -= overscan.top;
+            inoutInsets.right -= overscan.right;
+            inoutInsets.bottom -= overscan.bottom;
+            return false;
+        }
+    }
+
+    /**
      * Sets whether or not this view should account for system screen decorations
      * such as the status bar and inset its content; that is, controlling whether
      * the default implementation of {@link #fitSystemWindows(Rect)} will be
@@ -17919,6 +17944,13 @@
 
         /**
          * For windows that are full-screen but using insets to layout inside
+         * of the screen areas, these are the current insets to appear inside
+         * the overscan area of the display.
+         */
+        final Rect mOverscanInsets = new Rect();
+
+        /**
+         * For windows that are full-screen but using insets to layout inside
          * of the screen decorations, these are the current insets for the
          * content of the window.
          */
@@ -18020,6 +18052,12 @@
         boolean mHasSystemUiListeners;
 
         /**
+         * Set if the window has requested to extend into the overscan region
+         * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN.
+         */
+        boolean mOverscanRequested;
+
+        /**
          * Set if the visibility of any views has changed.
          */
         boolean mViewVisibilityChanged;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9b6dafb..b8fae865 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -229,6 +229,7 @@
     boolean mIsDrawing;
     int mLastSystemUiVisibility;
     int mClientWindowLayoutFlags;
+    boolean mLastOverscanRequested;
 
     /** @hide */
     public static final int EVENT_NOT_HANDLED = 0;
@@ -262,6 +263,7 @@
     // These are accessed by multiple threads.
     final Rect mWinFrame; // frame given by window manager.
 
+    final Rect mPendingOverscanInsets = new Rect();
     final Rect mPendingVisibleInsets = new Rect();
     final Rect mPendingContentInsets = new Rect();
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
@@ -566,6 +568,7 @@
                 if (mTranslator != null) {
                     mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
                 }
+                mPendingOverscanInsets.set(0, 0, 0, 0);
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
                 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
@@ -1255,6 +1258,9 @@
                 mAttachInfo.mInTouchMode = !mAddedTouchMode;
                 ensureTouchModeLocally(mAddedTouchMode);
             } else {
+                if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) {
+                    insetsChanged = true;
+                }
                 if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
                     insetsChanged = true;
                 }
@@ -1320,15 +1326,20 @@
             }
         }
 
-        if (params != null && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
-            if (!PixelFormat.formatHasAlpha(params.format)) {
-                params.format = PixelFormat.TRANSLUCENT;
+        if (params != null) {
+            if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
+                if (!PixelFormat.formatHasAlpha(params.format)) {
+                    params.format = PixelFormat.TRANSLUCENT;
+                }
             }
+            mAttachInfo.mOverscanRequested = (params.flags
+                    & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
         }
 
         if (mFitSystemWindowsRequested) {
             mFitSystemWindowsRequested = false;
             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+            mLastOverscanRequested = mAttachInfo.mOverscanRequested;
             host.fitSystemWindows(mFitSystemWindowsInsets);
             if (mLayoutRequested) {
                 // Short-circuit catching a new layout request here, so
@@ -1383,7 +1394,6 @@
 
             boolean hwInitialized = false;
             boolean contentInsetsChanged = false;
-            boolean visibleInsetsChanged;
             boolean hadSurface = mSurface.isValid();
 
             try {
@@ -1396,6 +1406,7 @@
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
                 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
+                        + " overscan=" + mPendingOverscanInsets.toShortString()
                         + " content=" + mPendingContentInsets.toShortString()
                         + " visible=" + mPendingVisibleInsets.toShortString()
                         + " surface=" + mSurface);
@@ -1407,9 +1418,11 @@
                     mPendingConfiguration.seq = 0;
                 }
 
+                final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
+                        mAttachInfo.mOverscanInsets);
                 contentInsetsChanged = !mPendingContentInsets.equals(
                         mAttachInfo.mContentInsets);
-                visibleInsetsChanged = !mPendingVisibleInsets.equals(
+                final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
                         mAttachInfo.mVisibleInsets);
                 if (contentInsetsChanged) {
                     if (mWidth > 0 && mHeight > 0 && lp != null &&
@@ -1486,9 +1499,18 @@
                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
                             + mAttachInfo.mContentInsets);
                 }
+                if (overscanInsetsChanged) {
+                    mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
+                            + mAttachInfo.mOverscanInsets);
+                    // Need to relayout with content insets.
+                    contentInsetsChanged = true;
+                }
                 if (contentInsetsChanged || mLastSystemUiVisibility !=
-                        mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested) {
+                        mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
+                        || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
+                    mLastOverscanRequested = mAttachInfo.mOverscanRequested;
                     mFitSystemWindowsRequested = false;
                     mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
                     host.fitSystemWindows(mFitSystemWindowsInsets);
@@ -2942,6 +2964,7 @@
                 // Recycled in the fall through...
                 SomeArgs args = (SomeArgs) msg.obj;
                 if (mWinFrame.equals(args.arg1)
+                        && mPendingOverscanInsets.equals(args.arg5)
                         && mPendingContentInsets.equals(args.arg2)
                         && mPendingVisibleInsets.equals(args.arg3)
                         && args.arg4 == null) {
@@ -2958,6 +2981,7 @@
                     }
 
                     mWinFrame.set((Rect) args.arg1);
+                    mPendingOverscanInsets.set((Rect) args.arg5);
                     mPendingContentInsets.set((Rect) args.arg2);
                     mPendingVisibleInsets.set((Rect) args.arg3);
 
@@ -4031,7 +4055,7 @@
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
-                mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
+                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                 mPendingConfiguration, mSurface);
         //Log.d(TAG, "<<<<<< BACK FROM relayout");
         if (restore) {
@@ -4040,6 +4064,7 @@
         
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
+            mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
             mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
             mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
         }
@@ -4245,7 +4270,7 @@
         mHandler.sendMessage(msg);
     }
 
-    public void dispatchResized(Rect frame, Rect contentInsets,
+    public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
         if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
@@ -4254,6 +4279,7 @@
         Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWindow(frame);
+            mTranslator.translateRectInScreenToAppWindow(overscanInsets);
             mTranslator.translateRectInScreenToAppWindow(contentInsets);
             mTranslator.translateRectInScreenToAppWindow(visibleInsets);
         }
@@ -4263,6 +4289,7 @@
         args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
         args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
         args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
+        args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
         msg.obj = args;
         mHandler.sendMessage(msg);
     }
@@ -4997,11 +5024,11 @@
             mWindowSession = viewAncestor.mWindowSession;
         }
 
-        public void resized(Rect frame, Rect contentInsets,
+        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
-                viewAncestor.dispatchResized(frame, contentInsets,
+                viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
                         visibleInsets, reportDraw, newConfig);
             }
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d236561..bf330f3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1193,6 +1193,37 @@
         public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;
 
         /**
+         * Value for {@link #rotationAnimation} to define the animation used to
+         * specify that this window will rotate in or out following a rotation.
+         */
+        public static final int ROTATION_ANIMATION_ROTATE = 0;
+
+        /**
+         * Value for {@link #rotationAnimation} to define the animation used to
+         * specify that this window will fade in or out following a rotation.
+         */
+        public static final int ROTATION_ANIMATION_CROSSFADE = 1;
+
+        /**
+         * Value for {@link #rotationAnimation} to define the animation used to
+         * specify that this window will immediately disappear or appear following
+         * a rotation.
+         */
+        public static final int ROTATION_ANIMATION_JUMPCUT = 2;
+
+        /**
+         * Define the animation used on this window for entry or exit following
+         * a rotation. This only works if the incoming and outgoing topmost
+         * opaque windows have the #FLAG_FULLSCREEN bit set and are not covered
+         * by other windows.
+         * 
+         * @see #ROTATION_ANIMATION_ROTATE
+         * @see #ROTATION_ANIMATION_CROSSFADE
+         * @see #ROTATION_ANIMATION_JUMPCUT
+         */
+        public int rotationAnimation = ROTATION_ANIMATION_ROTATE;
+
+        /**
          * Identifier for this window.  This will usually be filled in for
          * you.
          */
@@ -1367,6 +1398,7 @@
             out.writeFloat(dimAmount);
             out.writeFloat(screenBrightness);
             out.writeFloat(buttonBrightness);
+            out.writeInt(rotationAnimation);
             out.writeStrongBinder(token);
             out.writeString(packageName);
             TextUtils.writeToParcel(mTitle, out, parcelableFlags);
@@ -1408,6 +1440,7 @@
             dimAmount = in.readFloat();
             screenBrightness = in.readFloat();
             buttonBrightness = in.readFloat();
+            rotationAnimation = in.readInt();
             token = in.readStrongBinder();
             packageName = in.readString();
             mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -1432,18 +1465,19 @@
         public static final int SOFT_INPUT_MODE_CHANGED = 1<<9;
         public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
         public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
+        public static final int ROTATION_ANIMATION_CHANGED = 1<<12;
         /** {@hide} */
-        public static final int BUTTON_BRIGHTNESS_CHANGED = 1<<12;
+        public static final int BUTTON_BRIGHTNESS_CHANGED = 1<<13;
         /** {@hide} */
-        public static final int SYSTEM_UI_VISIBILITY_CHANGED = 1<<13;
+        public static final int SYSTEM_UI_VISIBILITY_CHANGED = 1<<14;
         /** {@hide} */
-        public static final int SYSTEM_UI_LISTENER_CHANGED = 1<<14;
+        public static final int SYSTEM_UI_LISTENER_CHANGED = 1<<15;
         /** {@hide} */
-        public static final int INPUT_FEATURES_CHANGED = 1<<15;
+        public static final int INPUT_FEATURES_CHANGED = 1<<16;
         /** {@hide} */
-        public static final int PRIVATE_FLAGS_CHANGED = 1<<16;
+        public static final int PRIVATE_FLAGS_CHANGED = 1<<17;
         /** {@hide} */
-        public static final int USER_ACTIVITY_TIMEOUT_CHANGED = 1<<17;
+        public static final int USER_ACTIVITY_TIMEOUT_CHANGED = 1<<18;
         /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
@@ -1543,6 +1577,10 @@
                 buttonBrightness = o.buttonBrightness;
                 changes |= BUTTON_BRIGHTNESS_CHANGED;
             }
+            if (rotationAnimation != o.rotationAnimation) {
+                rotationAnimation = o.rotationAnimation;
+                changes |= ROTATION_ANIMATION_CHANGED;
+            }
     
             if (screenOrientation != o.screenOrientation) {
                 screenOrientation = o.screenOrientation;
@@ -1645,6 +1683,10 @@
                 sb.append(" bbrt=");
                 sb.append(buttonBrightness);
             }
+            if (rotationAnimation != ROTATION_ANIMATION_ROTATE) {
+                sb.append(" rotAnim=");
+                sb.append(rotationAnimation);
+            }
             if ((flags & FLAG_COMPATIBLE_WINDOW) != 0) {
                 sb.append(" compatible=true");
             }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 192eded..c0044b6 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -154,6 +154,8 @@
          * @param displayFrame The frame of the overall display in which this
          * window can appear, used for constraining the overall dimensions
          * of the window.
+         * @param overlayFrame The frame within the display that is inside
+         * of the overlay region.
          * @param contentFrame The frame within the display in which we would
          * like active content to appear.  This will cause windows behind to
          * be resized to match the given content frame.
@@ -165,7 +167,7 @@
          * are visible.
          */
         public void computeFrameLw(Rect parentFrame, Rect displayFrame,
-                Rect contentFrame, Rect visibleFrame);
+                Rect overlayFrame, Rect contentFrame, Rect visibleFrame);
 
         /**
          * Retrieve the current frame of the window that has been assigned by
@@ -193,6 +195,15 @@
         public Rect getDisplayFrameLw();
 
         /**
+         * Retrieve the frame of the area inside the overscan region of the
+         * display that this window was last laid out in.  Must be called with the
+         * window manager lock held.
+         *
+         * @return Rect The rectangle holding the display overscan frame.
+         */
+        public Rect getOverscanFrameLw();
+
+        /**
          * Retrieve the frame of the content area that this window was last
          * laid out in.  This is the area in which the content of the window
          * should be placed.  It will be smaller than the display frame to
@@ -684,6 +695,31 @@
     public int selectAnimationLw(WindowState win, int transit);
 
     /**
+     * Determine the animation to run for a rotation transition based on the
+     * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
+     * and whether it is currently fullscreen and frontmost.
+     * 
+     * @param anim The exiting animation resource id is stored in anim[0], the 
+     * entering animation resource id is stored in anim[1].
+     */
+    public void selectRotationAnimationLw(int anim[]);
+
+    /**
+     * Validate whether the current top fullscreen has specified the same
+     * {@link WindowManager.LayoutParams#rotationAnimation} value as that
+     * being passed in from the previous top fullscreen window.
+     *
+     * @param exitAnimId exiting resource id from the previous window.
+     * @param enterAnimId entering resource id from the previous window.
+     * @param forceDefault For rotation animations only, if true ignore the
+     * animation values and just return false.
+     * @return true if the previous values are still valid, false if they
+     * should be replaced with the default.
+     */
+    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
+            boolean forceDefault);
+
+    /**
      * Create and return an animation to re-display a force hidden window.
      */
     public Animation createForceHideEnterAnimation(boolean onWallpaper);
@@ -909,6 +945,7 @@
      * @see android.app.KeyguardManager.KeyguardLock#disableKeyguard()
      * @see android.app.KeyguardManager.KeyguardLock#reenableKeyguard()
      */
+    @SuppressWarnings("javadoc")
     public void enableKeyguard(boolean enabled);
 
     /**
@@ -924,6 +961,7 @@
      * @param callback Callback to send the result back.
      * @see android.app.KeyguardManager#exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult)
      */
+    @SuppressWarnings("javadoc")
     void exitKeyguardSecurely(OnKeyguardExitResult callback);
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d0bfbe8..1321515 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -334,7 +334,8 @@
          * See {@link WebView#capturePicture} for details of the picture.
          *
          * @param view the WebView that owns the picture
-         * @param picture the new picture
+         * @param picture the new picture. Applications targetting Jelly
+         *         Bean MR2 or above will always receive a null Picture.
          * @deprecated Deprecated due to internal changes.
          */
         @Deprecated
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 3ded1cd..19784a4 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -7909,7 +7909,11 @@
         if (mPictureListener != null) {
             // trigger picture listener for hardware layers. Software layers are
             // triggered in setNewPicture
-            mPictureListener.onNewPicture(getWebView(), capturePicture());
+            // TODO: Update CUR_DEVELOPMENT when appropriate JBMR2 constant is
+            // available.
+            Picture picture = mContext.getApplicationInfo().targetSdkVersion <
+                    Build.VERSION_CODES.CUR_DEVELOPMENT ? capturePicture() : null;
+            mPictureListener.onNewPicture(getWebView(), picture);
         }
     }
 
@@ -7994,7 +7998,11 @@
                     || mWebView.getLayerType() == View.LAYER_TYPE_SOFTWARE) {
                 // trigger picture listener for software layers. Hardware layers are
                 // triggered in pageSwapCallback
-                mPictureListener.onNewPicture(getWebView(), capturePicture());
+                // TODO: Update CUR_DEVELOPMENT when appropriate JBMR2 constant is
+                // available.
+                Picture picture = mContext.getApplicationInfo().targetSdkVersion <
+                        Build.VERSION_CODES.CUR_DEVELOPMENT ? capturePicture() : null;
+                mPictureListener.onNewPicture(getWebView(), picture);
             }
         }
     }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 69e3177..4436fbb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2429,7 +2429,9 @@
         View selectedView = getSelectedView();
         int selectedPos = mSelectedPosition;
 
-        int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
+        int nextSelectedPosition = (direction == View.FOCUS_DOWN) ?
+                lookForSelectablePosition(selectedPos + 1, true) :
+                lookForSelectablePosition(selectedPos - 1, false);
         int amountToScroll = amountToScroll(direction, nextSelectedPosition);
 
         // if we are moving focus, we may OVERRIDE the default behavior
@@ -2641,14 +2643,18 @@
         final int listBottom = getHeight() - mListPadding.bottom;
         final int listTop = mListPadding.top;
 
-        final int numChildren = getChildCount();
+        int numChildren = getChildCount();
 
         if (direction == View.FOCUS_DOWN) {
             int indexToMakeVisible = numChildren - 1;
             if (nextSelectedPosition != INVALID_POSITION) {
                 indexToMakeVisible = nextSelectedPosition - mFirstPosition;
             }
-
+            while (numChildren <= indexToMakeVisible) {
+                // Child to view is not attached yet.
+                addViewBelow(getChildAt(numChildren - 1), mFirstPosition + numChildren - 1);
+                numChildren++;
+            }
             final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
             final View viewToMakeVisible = getChildAt(indexToMakeVisible);
 
@@ -2682,6 +2688,12 @@
             if (nextSelectedPosition != INVALID_POSITION) {
                 indexToMakeVisible = nextSelectedPosition - mFirstPosition;
             }
+            while (indexToMakeVisible < 0) {
+                // Child to view is not attached yet.
+                addViewAbove(getChildAt(0), mFirstPosition);
+                mFirstPosition--;
+                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
+            }
             final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
             final View viewToMakeVisible = getChildAt(indexToMakeVisible);
             int goalTop = listTop;
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
index 78b4466..6d51d38 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
@@ -22,9 +22,9 @@
 
 /** {@hide} */
 oneway interface IAppWidgetHost {
-    void updateAppWidget(int appWidgetId, in RemoteViews views);
-    void providerChanged(int appWidgetId, in AppWidgetProviderInfo info);
-    void providersChanged();
-    void viewDataChanged(int appWidgetId, int viewId);
+    void updateAppWidget(int appWidgetId, in RemoteViews views, int userId);
+    void providerChanged(int appWidgetId, in AppWidgetProviderInfo info, int userId);
+    void providersChanged(int userId);
+    void viewDataChanged(int appWidgetId, int viewId, int userId);
 }
 
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index e685e63..7ddd5d2 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -26,42 +26,39 @@
 
 /** {@hide} */
 interface IAppWidgetService {
-    
+
     //
     // for AppWidgetHost
     //
     int[] startListening(IAppWidgetHost host, String packageName, int hostId,
-            out List<RemoteViews> updatedViews);
-    int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId,
             out List<RemoteViews> updatedViews, int userId);
-    void stopListening(int hostId);
-    void stopListeningAsUser(int hostId, int userId);
-    int allocateAppWidgetId(String packageName, int hostId);
-    void deleteAppWidgetId(int appWidgetId);
-    void deleteHost(int hostId);
-    void deleteAllHosts();
-    RemoteViews getAppWidgetViews(int appWidgetId);
-    int[] getAppWidgetIdsForHost(int hostId);
+    void stopListening(int hostId, int userId);
+    int allocateAppWidgetId(String packageName, int hostId, int userId);
+    void deleteAppWidgetId(int appWidgetId, int userId);
+    void deleteHost(int hostId, int userId);
+    void deleteAllHosts(int userId);
+    RemoteViews getAppWidgetViews(int appWidgetId, int userId);
+    int[] getAppWidgetIdsForHost(int hostId, int userId);
 
     //
     // for AppWidgetManager
     //
-    void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
-    void updateAppWidgetOptions(int appWidgetId, in Bundle extras);
-    Bundle getAppWidgetOptions(int appWidgetId);
-    void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
-    void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views);
-    void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, int viewId);
-    List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter);
-    AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
-    boolean hasBindAppWidgetPermission(in String packageName);
-    void setBindAppWidgetPermission(in String packageName, in boolean permission);
-    void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options);
-    boolean bindAppWidgetIdIfAllowed(
-            in String packageName, int appWidgetId, in ComponentName provider, in Bundle options);
+    void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views, int userId);
+    void updateAppWidgetOptions(int appWidgetId, in Bundle extras, int userId);
+    Bundle getAppWidgetOptions(int appWidgetId, int userId);
+    void partiallyUpdateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views, int userId);
+    void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views, int userId);
+    void notifyAppWidgetViewDataChanged(in int[] appWidgetIds, int viewId, int userId);
+    List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId);
+    AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId);
+    boolean hasBindAppWidgetPermission(in String packageName, int userId);
+    void setBindAppWidgetPermission(in String packageName, in boolean permission, int userId);
+    void bindAppWidgetId(int appWidgetId, in ComponentName provider, in Bundle options, int userId);
+    boolean bindAppWidgetIdIfAllowed(in String packageName, int appWidgetId,
+            in ComponentName provider, in Bundle options, int userId);
     void bindRemoteViewsService(int appWidgetId, in Intent intent, in IBinder connection, int userId);
     void unbindRemoteViewsService(int appWidgetId, in Intent intent, int userId);
-    int[] getAppWidgetIds(in ComponentName provider);
+    int[] getAppWidgetIds(in ComponentName provider, int userId);
 
 }
 
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index 88e58dc..6fb72f1 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -39,6 +39,7 @@
     public Object arg2;
     public Object arg3;
     public Object arg4;
+    public Object arg5;
     public int argi1;
     public int argi2;
     public int argi3;
@@ -85,6 +86,7 @@
         arg2 = null;
         arg3 = null;
         arg4 = null;
+        arg5 = null;
         argi1 = 0;
         argi2 = 0;
         argi3 = 0;
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 28fd05f..58d4aa7 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -520,7 +520,6 @@
             return mDstState;
         }
 
-
         /**
          * @return the original state that received the message.
          */
@@ -551,7 +550,7 @@
             } else {
                 sb.append(what);
             }
-            if ( ! TextUtils.isEmpty(mInfo)) {
+            if (!TextUtils.isEmpty(mInfo)) {
                 sb.append(" ");
                 sb.append(mInfo);
             }
@@ -656,8 +655,7 @@
          *
          */
         synchronized void add(StateMachine sm, Message msg, String messageInfo, IState state,
-                IState orgState,
-                IState transToState) {
+                IState orgState, IState transToState) {
             mCount += 1;
             if (mLogRecVector.size() < mMaxSize) {
                 mLogRecVector.add(new LogRec(sm, msg, messageInfo, state, orgState, transToState));
@@ -672,7 +670,6 @@
         }
     }
 
-
     private static class SmHandler extends Handler {
 
         /** The debug flag */
@@ -730,15 +727,13 @@
              */
             @Override
             public String toString() {
-                return "state=" + state.getName() + ",active=" + active
-                        + ",parent=" + ((parentStateInfo == null) ?
-                                        "null" : parentStateInfo.state.getName());
+                return "state=" + state.getName() + ",active=" + active + ",parent="
+                        + ((parentStateInfo == null) ? "null" : parentStateInfo.state.getName());
             }
         }
 
         /** The map of all of the states in the state machine */
-        private HashMap<State, StateInfo> mStateInfo =
-            new HashMap<State, StateInfo>();
+        private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();
 
         /** The initial state that will process the first message */
         private State mInitialState;
@@ -788,14 +783,14 @@
             if (mIsConstructionCompleted) {
                 /** Normal path */
                 msgProcessedState = processMsg(msg);
-            } else if (!mIsConstructionCompleted &&
-                    (mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) {
+            } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
+                    && (mMsg.obj == mSmHandlerObj)) {
                 /** Initial one time path. */
                 mIsConstructionCompleted = true;
                 invokeEnterMethods(0);
             } else {
-                throw new RuntimeException("StateMachine.handleMessage: " +
-                            "The start method not called, received msg: " + msg);
+                throw new RuntimeException("StateMachine.handleMessage: "
+                        + "The start method not called, received msg: " + msg);
             }
             performTransitions(msgProcessedState, msg);
 
@@ -830,8 +825,8 @@
                 }
             } else if (recordLogMsg) {
                 /** Record message */
-               mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
-                        orgState, mDestState);
+                mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState,
+                        mDestState);
             }
 
             State destState = mDestState;
@@ -852,7 +847,6 @@
                     int stateStackEnteringIndex = moveTempStateStackToStateStack();
                     invokeEnterMethods(stateStackEnteringIndex);
 
-
                     /**
                      * Since we have transitioned to a new state we need to have
                      * any deferred messages moved to the front of the message queue
@@ -979,7 +973,7 @@
                         mSm.log("processMsg: " + curStateInfo.state.getName());
                     }
                 }
-           }
+            }
             return (curStateInfo != null) ? curStateInfo.state : null;
         }
 
@@ -988,8 +982,8 @@
          * up to the common ancestor state.
          */
         private final void invokeExitMethods(StateInfo commonStateInfo) {
-            while ((mStateStackTopIndex >= 0) &&
-                    (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
+            while ((mStateStackTopIndex >= 0)
+                    && (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
                 State curState = mStateStack[mStateStackTopIndex].state;
                 if (mDbg) mSm.log("invokeExitMethods: " + curState.getName());
                 curState.exit();
@@ -1019,7 +1013,7 @@
              * as the most resent message and end with the oldest
              * messages at the front of the queue.
              */
-            for (int i = mDeferredMessages.size() - 1; i >= 0; i-- ) {
+            for (int i = mDeferredMessages.size() - 1; i >= 0; i--) {
                 Message curMsg = mDeferredMessages.get(i);
                 if (mDbg) mSm.log("moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
                 sendMessageAtFrontOfQueue(curMsg);
@@ -1047,9 +1041,9 @@
 
             mStateStackTopIndex = j - 1;
             if (mDbg) {
-                mSm.log("moveTempStackToStateStack: X mStateStackTop="
-                      + mStateStackTopIndex + ",startingIndex=" + startingIndex
-                      + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
+                mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
+                        + ",startingIndex=" + startingIndex + ",Top="
+                        + mStateStack[mStateStackTopIndex].state.getName());
             }
             return startingIndex;
         }
@@ -1081,7 +1075,7 @@
 
             if (mDbg) {
                 mSm.log("setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
-                      + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
+                        + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
             }
             return curStateInfo;
         }
@@ -1091,8 +1085,7 @@
          */
         private final void setupInitialStateStack() {
             if (mDbg) {
-                mSm.log("setupInitialStateStack: E mInitialState="
-                    + mInitialState.getName());
+                mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());
             }
 
             StateInfo curStateInfo = mStateInfo.get(mInitialState);
@@ -1132,8 +1125,8 @@
          */
         private final StateInfo addState(State state, State parent) {
             if (mDbg) {
-                mSm.log("addStateInternal: E state=" + state.getName()
-                        + ",parent=" + ((parent == null) ? "" : parent.getName()));
+                mSm.log("addStateInternal: E state=" + state.getName() + ",parent="
+                        + ((parent == null) ? "" : parent.getName()));
             }
             StateInfo parentStateInfo = null;
             if (parent != null) {
@@ -1150,9 +1143,9 @@
             }
 
             // Validate that we aren't adding the same state in two different hierarchies.
-            if ((stateInfo.parentStateInfo != null) &&
-                    (stateInfo.parentStateInfo != parentStateInfo)) {
-                    throw new RuntimeException("state already added");
+            if ((stateInfo.parentStateInfo != null)
+                    && (stateInfo.parentStateInfo != parentStateInfo)) {
+                throw new RuntimeException("state already added");
             }
             stateInfo.state = state;
             stateInfo.parentStateInfo = parentStateInfo;
@@ -1509,8 +1502,7 @@
      *
      * @return  A Message object from the global pool
      */
-    public final Message obtainMessage()
-    {
+    public final Message obtainMessage() {
         return Message.obtain(mSmHandler);
     }
 
@@ -1542,8 +1534,7 @@
      * @param obj is assigned to Message.obj.
      * @return  A Message object from the global pool
      */
-    public final Message obtainMessage(int what, Object obj)
-    {
+    public final Message obtainMessage(int what, Object obj) {
         return Message.obtain(mSmHandler, what, obj);
     }
 
@@ -1561,8 +1552,7 @@
      * @param arg2  is assigned to Message.arg2
      * @return  A Message object from the global pool
      */
-    public final Message obtainMessage(int what, int arg1, int arg2)
-    {
+    public final Message obtainMessage(int what, int arg1, int arg2) {
         return Message.obtain(mSmHandler, what, arg1, arg2);
     }
 
@@ -1581,8 +1571,7 @@
      * @param obj is assigned to Message.obj
      * @return  A Message object from the global pool
      */
-    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
-    {
+    public final Message obtainMessage(int what, int arg1, int arg2, Object obj) {
         return Message.obtain(mSmHandler, what, arg1, arg2, obj);
     }
 
@@ -1609,7 +1598,7 @@
         SmHandler smh = mSmHandler;
         if (smh == null) return;
 
-        smh.sendMessage(obtainMessage(what,obj));
+        smh.sendMessage(obtainMessage(what, obj));
     }
 
     /**
@@ -1798,34 +1787,84 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(getName() + ":");
         pw.println(" total records=" + getLogRecCount());
-        for (int i=0; i < getLogRecSize(); i++) {
+        for (int i = 0; i < getLogRecSize(); i++) {
             pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString());
             pw.flush();
         }
         pw.println("curState=" + getCurrentState().getName());
     }
 
+    /**
+     * Log with debug and add to the LogRecords.
+     *
+     * @param s is string log
+     */
+    protected void logAndAddLogRec(String s) {
+        addLogRec(s);
+        log(s);
+    }
+
+    /**
+     * Log with debug
+     *
+     * @param s is string log
+     */
     protected void log(String s) {
         Log.d(mName, s);
     }
 
-    protected void logv(String s) {
-        Log.v(mName, s);
-    }
-
-    protected void logi(String s) {
-        Log.i(mName, s);
-    }
-
+    /**
+     * Log with debug attribute
+     *
+     * @param s is string log
+     */
     protected void logd(String s) {
         Log.d(mName, s);
     }
 
+    /**
+     * Log with verbose attribute
+     *
+     * @param s is string log
+     */
+    protected void logv(String s) {
+        Log.v(mName, s);
+    }
+
+    /**
+     * Log with info attribute
+     *
+     * @param s is string log
+     */
+    protected void logi(String s) {
+        Log.i(mName, s);
+    }
+
+    /**
+     * Log with warning attribute
+     *
+     * @param s is string log
+     */
     protected void logw(String s) {
         Log.w(mName, s);
     }
 
+    /**
+     * Log with error attribute
+     *
+     * @param s is string log
+     */
     protected void loge(String s) {
         Log.e(mName, s);
     }
+
+    /**
+     * Log with error attribute
+     *
+     * @param s is string log
+     * @param e is a Throwable which logs additional information.
+     */
+    protected void loge(String s, Throwable e) {
+        Log.e(mName, s, e);
+    }
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index b76e89d..02bd4ac 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -34,7 +34,7 @@
     }
 
     @Override
-    public void resized(Rect frame, Rect contentInsets,
+    public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
         if (reportDraw) {
             try {
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index a129496..18a696e 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -41,7 +41,7 @@
     private ActionBarView mActionView;
     private View mActionBarBottom;
     private int mLastSystemUiVisibility;
-    private final Rect mZeroRect = new Rect(0, 0, 0, 0);
+    private final Rect mLocalInsets = new Rect();
 
     static final int[] mActionBarSizeAttr = new int [] {
             com.android.internal.R.attr.actionBarSize
@@ -165,13 +165,8 @@
         // make sure its content is not being covered by system UI...  though it
         // will still be covered by the action bar since they have requested it to
         // overlay.
-        if ((vis & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
-            changed |= applyInsets(mContent, insets, true, true, true, true);
-            // The insets are now consumed.
-            insets.set(0, 0, 0, 0);
-        } else {
-            changed |= applyInsets(mContent, mZeroRect, true, true, true, true);
-        }
+        boolean res = computeFitSystemWindows(insets, mLocalInsets);
+        changed |= applyInsets(mContent, mLocalInsets, true, true, true, true);
 
 
         if (stable || mActionBarTop.getVisibility() == VISIBLE) {
@@ -190,7 +185,7 @@
         if (mActionView.isSplitActionBar()) {
             if (stable || (mActionBarBottom != null
                     && mActionBarBottom.getVisibility() == VISIBLE)) {
-                // If action bar is split, adjust buttom insets for it.
+                // If action bar is split, adjust bottom insets for it.
                 insets.bottom += mActionBarHeight;
             }
         }
@@ -199,7 +194,8 @@
             requestLayout();
         }
 
-        return super.fitSystemWindows(insets);
+        super.fitSystemWindows(insets);
+        return true;
     }
 
     void pullChildren() {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c6b7631..2544c54 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -162,7 +162,8 @@
 	external/skia/include/effects \
 	external/skia/include/images \
 	external/skia/include/ports \
-	external/skia/src/ports \
+	external/skia/src/core \
+	external/skia/src/images \
 	external/skia/include/utils \
 	external/sqlite/dist \
 	external/sqlite/android \
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index b7fdecf..daabce3 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -231,7 +231,7 @@
     }
 
     SkAutoTDelete<SkImageDecoder> add(decoder);
-    SkAutoTDelete<SkBitmap> adb(bitmap, !useExistingBitmap);
+    SkAutoTDelete<SkBitmap> adb(!useExistingBitmap ? bitmap : NULL);
 
     decoder->setPeeker(&peeker);
     if (!isPurgeable) {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 886eb6e..6410bc3 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -65,6 +65,16 @@
         return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
     }
     
+    static void copyCanvasState(JNIEnv* env, jobject clazz,
+                                SkCanvas* srcCanvas, SkCanvas* dstCanvas) {
+        if (srcCanvas && dstCanvas) {
+            if (NULL != srcCanvas->getDevice() && NULL != dstCanvas->getDevice()) {
+                dstCanvas->clipRegion(srcCanvas->getTotalClip());
+            }
+            dstCanvas->setMatrix(srcCanvas->getTotalMatrix());
+        }
+    }
+
     static void freeCaches(JNIEnv* env, jobject) {
         // these are called in no particular order
         SkImageRef_GlobalPool::SetRAMUsed(0);
@@ -93,14 +103,6 @@
         return canvas->getDevice()->accessBitmap(false).height();
     }
 
-    static void setBitmap(JNIEnv* env, jobject, SkCanvas* canvas, SkBitmap* bitmap) {
-        if (bitmap) {
-            canvas->setBitmapDevice(*bitmap);
-        } else {
-            canvas->setDevice(NULL);
-        }
-    }
- 
     static int saveAll(JNIEnv* env, jobject jcanvas) {
         NPE_CHECK_RETURN_ZERO(env, jcanvas);
         return GraphicsJNI::getNativeCanvas(env, jcanvas)->save();
@@ -278,25 +280,25 @@
         canvas->setDrawFilter(filter);
     }
     
-    static jboolean quickReject__RectFI(JNIEnv* env, jobject, SkCanvas* canvas,
-                                        jobject rect, int edgetype) {
+    static jboolean quickReject__RectF(JNIEnv* env, jobject, SkCanvas* canvas,
+                                        jobject rect) {
         SkRect rect_;
         GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
-        return canvas->quickReject(rect_, (SkCanvas::EdgeType)edgetype);
+        return canvas->quickReject(rect_);
     }
- 
-    static jboolean quickReject__PathI(JNIEnv* env, jobject, SkCanvas* canvas,
-                                       SkPath* path, int edgetype) {
-        return canvas->quickReject(*path, (SkCanvas::EdgeType)edgetype);
+
+    static jboolean quickReject__Path(JNIEnv* env, jobject, SkCanvas* canvas,
+                                       SkPath* path) {
+        return canvas->quickReject(*path);
     }
- 
-    static jboolean quickReject__FFFFI(JNIEnv* env, jobject, SkCanvas* canvas,
+
+    static jboolean quickReject__FFFF(JNIEnv* env, jobject, SkCanvas* canvas,
                                        jfloat left, jfloat top, jfloat right,
-                                       jfloat bottom, int edgetype) {
+                                       jfloat bottom) {
         SkRect r;
         r.set(SkFloatToScalar(left), SkFloatToScalar(top),
               SkFloatToScalar(right), SkFloatToScalar(bottom));
-        return canvas->quickReject(r, (SkCanvas::EdgeType)edgetype);
+        return canvas->quickReject(r);
     }
  
     static void drawRGB(JNIEnv* env, jobject, SkCanvas* canvas,
@@ -930,12 +932,19 @@
                               jobject bounds) {
         SkRect   r;
         SkIRect ir;
-        bool     result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
+        bool     result = canvas->getClipBounds(&r);
 
         if (!result) {
             r.setEmpty();
+        } else {
+            // ensure the clip is not larger than the canvas
+            SkRect canvasRect;
+            SkISize deviceSize = canvas->getDeviceSize();
+            canvasRect.iset(0, 0, deviceSize.fWidth, deviceSize.fHeight);
+            r.intersect(canvasRect);
         }
         r.round(&ir);
+
         (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
         return result;
     }
@@ -949,10 +958,10 @@
 static JNINativeMethod gCanvasMethods[] = {
     {"finalizer", "(I)V", (void*) SkCanvasGlue::finalizer},
     {"initRaster","(I)I", (void*) SkCanvasGlue::initRaster},
+    {"copyNativeCanvasState","(II)V", (void*) SkCanvasGlue::copyCanvasState},
     {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque},
     {"getWidth","()I", (void*) SkCanvasGlue::getWidth},
     {"getHeight","()I", (void*) SkCanvasGlue::getHeight},
-    {"native_setBitmap","(II)V", (void*) SkCanvasGlue::setBitmap},
     {"save","()I", (void*) SkCanvasGlue::saveAll},
     {"save","(I)I", (void*) SkCanvasGlue::save},
     {"native_saveLayer","(ILandroid/graphics/RectF;II)I",
@@ -984,10 +993,10 @@
     {"native_getClipBounds","(ILandroid/graphics/Rect;)Z",
         (void*) SkCanvasGlue::getClipBounds},
     {"native_getCTM", "(II)V", (void*)SkCanvasGlue::getCTM},
-    {"native_quickReject","(ILandroid/graphics/RectF;I)Z",
-        (void*) SkCanvasGlue::quickReject__RectFI},
-    {"native_quickReject","(III)Z", (void*) SkCanvasGlue::quickReject__PathI},
-    {"native_quickReject","(IFFFFI)Z", (void*)SkCanvasGlue::quickReject__FFFFI},
+    {"native_quickReject","(ILandroid/graphics/RectF;)Z",
+        (void*) SkCanvasGlue::quickReject__RectF},
+    {"native_quickReject","(II)Z", (void*) SkCanvasGlue::quickReject__Path},
+    {"native_quickReject","(IFFFF)Z", (void*)SkCanvasGlue::quickReject__FFFF},
     {"native_drawRGB","(IIII)V", (void*) SkCanvasGlue::drawRGB},
     {"native_drawARGB","(IIIII)V", (void*) SkCanvasGlue::drawARGB},
     {"native_drawColor","(II)V", (void*) SkCanvasGlue::drawColor__I},
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index ff0eb45..01e7e3e 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -105,7 +105,7 @@
 void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
                        const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
                        const SkPaint* paint, SkRegion** outRegion) {
-    if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
+    if (canvas && canvas->quickReject(bounds)) {
         return;
     }
 
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index ab7cf46..ded2186 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -177,7 +177,7 @@
 
     SkRegion* region = new SkRegion;
     size_t size = p->readInt32();
-    region->unflatten(p->readInplace(size));
+    region->readFromMemory(p->readInplace(size));
 
     return region;
 }
@@ -190,9 +190,9 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    size_t size = region->flatten(NULL);
+    size_t size = region->writeToMemory(NULL);
     p->writeInt32(size);
-    region->flatten(p->writeInplace(size));
+    region->writeToMemory(p->writeInplace(size));
 
     return true;
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 60c6183..1a8612e 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -340,7 +340,7 @@
 }
 
 void TextLayoutShaper::init() {
-    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal);
+    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
 }
 
 void TextLayoutShaper::unrefTypefaces() {
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 7f4c37b..e056b61 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -147,25 +147,6 @@
     return SkTypeface::CreateFromFile(str.c_str());
 }
 
-#define MIN_GAMMA   (0.1f)
-#define MAX_GAMMA   (10.0f)
-static float pinGamma(float gamma) {
-    if (gamma < MIN_GAMMA) {
-        gamma = MIN_GAMMA;
-    } else if (gamma > MAX_GAMMA) {
-        gamma = MAX_GAMMA;
-    }
-    return gamma;
-}
-
-extern void skia_set_text_gamma(float, float);
-
-static void Typeface_setGammaForText(JNIEnv* env, jobject, jfloat blackGamma,
-                                     jfloat whiteGamma) {
-    // Comment this out for release builds. This is only used during development
-    skia_set_text_gamma(pinGamma(blackGamma), pinGamma(whiteGamma));
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gTypefaceMethods[] = {
@@ -177,7 +158,6 @@
                                            (void*)Typeface_createFromAsset },
     { "nativeCreateFromFile",     "(Ljava/lang/String;)I",
                                            (void*)Typeface_createFromFile },
-    { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
 };
 
 int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 7c65662..c0e12da 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -537,7 +537,10 @@
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
     if (camera == 0) return;
 
-    sp<Surface> surface = android_view_Surface_getSurface(env, jSurface);
+    sp<Surface> surface;
+    if (jSurface) {
+        surface = android_view_Surface_getSurface(env, jSurface);
+    }
 
     if (camera->setPreviewDisplay(surface) != NO_ERROR) {
         jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 26fc261..196004a 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -1,5 +1,4 @@
 /*
-**
 ** Copyright 2012, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -605,7 +604,7 @@
     jint _remaining;
     EGLint *attrib_list = (EGLint *) 0;
     android::sp<ANativeWindow> window;
-    android::sp<android::GLConsumer> surfaceTexture;
+    android::sp<android::GLConsumer> glConsumer;
 
     if (!attrib_list_ref) {
         _exception = 1;
@@ -626,12 +625,12 @@
         _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface";
         goto exit;
     }
-    surfaceTexture = android::SurfaceTexture_getSurfaceTexture(_env, win);
+    glConsumer = android::SurfaceTexture_getSurfaceTexture(_env, win);
 
-    if (surfaceTexture == NULL)
+    if (glConsumer == NULL)
         goto not_valid_surface;
 
-    window = new android::Surface(surfaceTexture->getBufferQueue());
+    window = new android::Surface(glConsumer->getBufferQueue());
 
     if (window == NULL)
         goto not_valid_surface;
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index c530117..a263f8b 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -2127,14 +2127,14 @@
     }
 }
 
-/* int glGetAttribLocation ( GLuint program, const char *name ) */
+/* GLint glGetAttribLocation ( GLuint program, const char *name ) */
 static jint
 android_glGetAttribLocation__ILjava_lang_String_2
   (JNIEnv *_env, jobject _this, jint program, jstring name) {
     jint _exception = 0;
     const char * _exceptionType;
     const char * _exceptionMessage;
-    int _returnValue = 0;
+    GLint _returnValue = 0;
     const char* _nativename = 0;
 
     if (!name) {
@@ -3983,14 +3983,14 @@
     }
 }
 
-/* int glGetUniformLocation ( GLuint program, const char *name ) */
+/* GLint glGetUniformLocation ( GLuint program, const char *name ) */
 static jint
 android_glGetUniformLocation__ILjava_lang_String_2
   (JNIEnv *_env, jobject _this, jint program, jstring name) {
     jint _exception = 0;
     const char * _exceptionType;
     const char * _exceptionMessage;
-    int _returnValue = 0;
+    GLint _returnValue = 0;
     const char* _nativename = 0;
 
     if (!name) {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 6724f36..6e21a11 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -159,7 +159,8 @@
             name = line + name_pos;
             nameLen = strlen(name);
 
-            if (strstr(name, "[heap]") == name) {
+            if ((strstr(name, "[heap]") == name) ||
+                (strstr(name, "/dev/ashmem/libc malloc") == name)) {
                 whichHeap = HEAP_NATIVE;
             } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
                 whichHeap = HEAP_DALVIK;
@@ -177,7 +178,8 @@
                 whichHeap = HEAP_APK;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
                 whichHeap = HEAP_TTF;
-            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) {
+            } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) ||
+                       (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
                 whichHeap = HEAP_DEX;
             } else if (nameLen > 0) {
                 whichHeap = HEAP_UNKNOWN_MAP;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index a6bb7c7..ba62f6d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -270,8 +270,7 @@
 // ----------------------------------------------------------------------------
 
 static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        SkCanvas::EdgeType edge) {
+        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
     return renderer->quickReject(left, top, right, bottom);
 }
 
@@ -961,7 +960,7 @@
     { "nSaveLayerAlpha",    "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayerAlpha },
     { "nSaveLayerAlpha",    "(III)I",          (void*) android_view_GLES20Canvas_saveLayerAlphaClip },
 
-    { "nQuickReject",       "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_quickReject },
+    { "nQuickReject",       "(IFFFF)Z",        (void*) android_view_GLES20Canvas_quickReject },
     { "nClipRect",          "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_clipRectF },
     { "nClipRect",          "(IIIIII)Z",       (void*) android_view_GLES20Canvas_clipRect },
     { "nClipPath",          "(III)Z",          (void*) android_view_GLES20Canvas_clipPath },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ab0d38e..b4a19f1 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -55,7 +55,6 @@
     jfieldID mNativeObject;
     jfieldID mGenerationId;
     jfieldID mCanvas;
-    jfieldID mCanvasSaveCount;
     jmethodID ctor;
 } gSurfaceClassInfo;
 
@@ -67,10 +66,15 @@
 } gRectClassInfo;
 
 static struct {
+    jfieldID mFinalizer;
     jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
 } gCanvasClassInfo;
 
+static struct {
+    jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
 // ----------------------------------------------------------------------------
 
 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
@@ -112,8 +116,8 @@
 
 // ----------------------------------------------------------------------------
 
-static bool isSurfaceValid(const sp<Surface>& sur) {
-    return sur != 0 && sur->getISurfaceTexture() != 0;
+static inline bool isSurfaceValid(const sp<Surface>& sur) {
+    return Surface::isValid(sur);
 }
 
 // ----------------------------------------------------------------------------
@@ -180,6 +184,15 @@
     }
 }
 
+static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
+  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
+  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
+          env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
+  env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
+  env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
+  SkSafeUnref(previousCanvas);
+}
+
 static jobject nativeLockCanvas(JNIEnv* env, jobject surfaceObj, jint nativeObject, jobject dirtyRectObj) {
     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
 
@@ -219,8 +232,6 @@
     jobject canvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
     env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
 
-    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
-            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
     SkBitmap bitmap;
     ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
     bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
@@ -233,7 +244,9 @@
         // be safe with an empty bitmap.
         bitmap.setPixels(NULL);
     }
-    nativeCanvas->setBitmapDevice(bitmap);
+
+    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
+    swapCanvasPtr(env, canvasObj, nativeCanvas);
 
     SkRegion clipReg;
     if (dirtyRegion.isRect()) { // very common case
@@ -250,9 +263,6 @@
 
     nativeCanvas->clipRegion(clipReg);
 
-    int saveCount = nativeCanvas->save();
-    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, saveCount);
-
     if (dirtyRectObj) {
         const Rect& bounds(dirtyRegion.getBounds());
         env->SetIntField(dirtyRectObj, gRectClassInfo.left, bounds.left);
@@ -277,12 +287,8 @@
     }
 
     // detach the canvas from the surface
-    SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
-            env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    int saveCount = env->GetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount);
-    nativeCanvas->restoreToCount(saveCount);
-    nativeCanvas->setBitmapDevice(SkBitmap());
-    env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, 0);
+    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+    swapCanvasPtr(env, canvasObj, nativeCanvas);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
@@ -382,14 +388,16 @@
             env->GetFieldID(gSurfaceClassInfo.clazz, "mGenerationId", "I");
     gSurfaceClassInfo.mCanvas =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
-    gSurfaceClassInfo.mCanvasSaveCount =
-            env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
-    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
+    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "()V");
 
     clazz = env->FindClass("android/graphics/Canvas");
+    gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
     gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
     gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
 
+    clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
+    gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
+
     clazz = env->FindClass("android/graphics/Rect");
     gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
     gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e477e54..a218488 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -110,6 +110,7 @@
     virtual void onUnlockPixels() {
     }
 
+    SK_DECLARE_UNFLATTENABLE_OBJECT()
 private:
     ScreenshotClient mScreenshot;
     SkColorTable*    fCTable;
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index e75a2d8..8a89db5 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -43,11 +43,16 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID nativeCanvas;
-    jfieldID surfaceFormat;
+    jfieldID mFinalizer;
+    jfieldID mNativeCanvas;
+    jfieldID mSurfaceFormat;
 } gCanvasClassInfo;
 
 static struct {
+    jfieldID mNativeCanvas;
+} gCanvasFinalizerClassInfo;
+
+static struct {
     jfieldID nativeWindow;
 } gTextureViewClassInfo;
 
@@ -120,6 +125,15 @@
     }
 }
 
+static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
+  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
+  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
+          env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
+  env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
+  env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
+  SkSafeUnref(previousCanvas);
+}
+
 static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
         jint nativeWindow, jobject canvas, jobject dirtyRect) {
 
@@ -157,9 +171,10 @@
         bitmap.setPixels(NULL);
     }
 
-    SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format);
-    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
-    nativeCanvas->setBitmapDevice(bitmap);
+    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
+
+    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
+    swapCanvasPtr(env, canvas, nativeCanvas);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -174,8 +189,8 @@
 static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
         jint nativeWindow, jobject canvas) {
 
-    SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
-    nativeCanvas->setBitmapDevice(SkBitmap());
+    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
+    swapCanvasPtr(env, canvas, nativeCanvas);
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -226,8 +241,12 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I");
-    GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I");
+    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
+    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
+    GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
+
+    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
+    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I");
 
     FIND_CLASS(clazz, "android/view/TextureView");
     GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I");
diff --git a/core/res/res/anim/rotation_animation_enter.xml b/core/res/res/anim/rotation_animation_enter.xml
new file mode 100644
index 0000000..a674e1d
--- /dev/null
+++ b/core/res/res/anim/rotation_animation_enter.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2013, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:duration="0"
+            android:interpolator="@interpolator/decelerate_quad" />
+</set>
diff --git a/core/res/res/anim/rotation_animation_jump_exit.xml b/core/res/res/anim/rotation_animation_jump_exit.xml
new file mode 100644
index 0000000..3338529
--- /dev/null
+++ b/core/res/res/anim/rotation_animation_jump_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2013, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="0"
+            android:interpolator="@interpolator/decelerate_quad" />
+</set>
diff --git a/core/res/res/anim/rotation_animation_xfade_exit.xml b/core/res/res/anim/rotation_animation_xfade_exit.xml
new file mode 100644
index 0000000..7300724
--- /dev/null
+++ b/core/res/res/anim/rotation_animation_xfade_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2013, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="500"
+            android:interpolator="@interpolator/decelerate_quad" />
+</set>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4cb7888..a64758c 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN-fout"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Raak om verbinding terug te stel"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
     <string name="reset" msgid="2448168080964209908">"Stel terug"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 54b5f6f..2a23541 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ሁልጊዜ የበራ VPN በመገናኘት ላይ…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ሁልጊዜ የበራ VPN ተገናኝቷል"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ሁልጊዜ የበራ VPN ስህተት"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"ግንኙነት ዳግም ለማስጀመር ይንኩ"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"ፋይል ምረጥ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ምንም ፋይል አልተመረጠም"</string>
     <string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a9ac95d..cba7680 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"جارٍ الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"تم الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"المس لإعادة تعيين الاتصال"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
     <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index c1cb9d59..a2284ce 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Памылка заўсёды ўключанага VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Націсніце, каб скінуць падключэнне"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
     <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 158134e..cc8ec59 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Установява се връзка с винаги включената виртуална частна мрежа (VPN)…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Установена е връзка с винаги включената виртуална частна мрежа (VPN)"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка във винаги включената виртуална частна мрежа (VPN)"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Докоснете, за да възстановите връзката"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string>
     <string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e3ee35d..4e8aa9c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"T\'estàs connectant a la VPN sempre activada…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Estàs connectat a la VPN sempre activada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toca per restablir la connexió"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string>
     <string name="reset" msgid="2448168080964209908">"Reinicia"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 35798a4..76c17de 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Připojování k trvalé síti VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Je připojena trvalá síť VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba trvalé sítě VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Klepnutím resetujete připojení"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string>
     <string name="reset" msgid="2448168080964209908">"Resetovat"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 477f313..6b01a68 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til Always-on VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN er forbundet"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i Always-on VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Tryk for at nulstille forbindelsen"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
     <string name="reset" msgid="2448168080964209908">"Nulstil"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 770cc61..7fb0014 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Verbindung zu durchgehend aktivem VPN wird hergestellt…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Mit durchgehend aktivem VPN verbunden"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Durchgehend aktives VPN – Verbindungsfehler"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Zum Zurücksetzen der Verbindung tippen"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string>
     <string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 5e3c56b..3307abf 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Σύνδεση πάντα ενεργοποιημένου VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Έχει συνδεθεί πάντα ενεργοποιημένο VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Αγγίξτε για επαναφορά της σύνδεσης"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Δεν έχει επιλεγεί αρχείο"</string>
     <string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4af1886..a695432 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Touch to reset connection"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
     <string name="reset" msgid="2448168080964209908">"Reset"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8517662..3aa900f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con la VPN siempre activada..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN siempre activada."</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN siempre activada."</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toca para restablecer la conexión."</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2b657c8..788c265c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Conectando VPN siempre activada…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN siempre activada conectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de VPN siempre activada"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toca para restablecer la conexión."</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string>
     <string name="reset" msgid="2448168080964209908">"Restablecer"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 3303f00..3312381e 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati sees VPN-i viga"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Ühenduse lähtestamiseks puudutage"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
     <string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b4a15c5..b6e3abe 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"در حال اتصال VPN همیشه فعال…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN همیشه فعال متصل شد"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"خطای VPN همیشه فعال"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"برای بازنشانی اتصال لمس کنید"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string>
     <string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 45f4a05..92712bc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Yhdistetään aina käytössä olevaan VPN-verkkoon..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Yhdistetty aina käytössä olevaan VPN-verkkoon"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Aina käytössä oleva VPN: virhe"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Nollaa yhteys koskettamalla"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string>
     <string name="reset" msgid="2448168080964209908">"Palauta"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c94946e..4c8ccc5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1062,7 +1062,7 @@
     <string name="noApplications" msgid="2991814273936504689">"Aucune application ne peut effectuer cette action."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"L\'application \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" s\'est arrêtée."</string>
-    <string name="aerr_process" msgid="4507058997035697579">"Malheureusement, le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est arrêté."</string>
+    <string name="aerr_process" msgid="4507058997035697579">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"L\'application <xliff:g id="APPLICATION">%2$s</xliff:g> ne répond pas."\n\n"Voulez-vous quitter ?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> ne répond pas."\n\n"Voulez-vous quitter ?"</string>
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Appuyez sur l\'écran pour réinitialiser la connexion."</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
     <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 3521f4b..057f620 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"हमेशा-चालू VPN कनेक्ट हो रहा है…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"हमेशा-चालू VPN कनेक्ट है"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"कनेक्शन रीसेट करने के लिए स्पर्श करें"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
     <string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ce7e954..cf566d7 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje s uvijek uključenom VPN mrežom…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan s uvijek uključenom VPN mrežom"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Pogreška uvijek uključene VPN mreže"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dodirnite za poništavanje veze"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d74810a..02c80a6 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -994,7 +994,7 @@
     <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
   </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"e napon: <xliff:g id="DATE">%s</xliff:g>"</string>
-    <string name="preposition_for_time" msgid="5506831244263083793">"ekkor: <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"év: <xliff:g id="YEAR">%s</xliff:g>"</string>
     <string name="day" msgid="8144195776058119424">"nap"</string>
     <string name="days" msgid="4774547661021344602">"nap"</string>
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Csatlakozás a mindig bekapcsolt VPN-hez..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Csatlakozva a mindig bekapcsolt VPN-hez"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Hiba a mindig bekapcsolt VPN-nel"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Érintse meg a kapcsolat alaphelyzetbe állításához."</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string>
     <string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d0b4d61..f0fd1ef 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Menyambungkan VPN selalu aktif..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN selalu aktif tersambung"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kesalahan VPN selalu aktif"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Sentuh untuk menyetel ulang sambungan"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Pilih file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string>
     <string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 87d21fe..ad9a94d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Connessione a VPN sempre attiva…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre attiva connessa"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Errore VPN sempre attiva"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Tocca per ripristinare la connessione"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Scegli file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nessun file è stato scelto"</string>
     <string name="reset" msgid="2448168080964209908">"Reimposta"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d698a77..9a2275b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ה-VPN שמופעל תמיד, מתחבר..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ה-VPN שפועל תמיד, מחובר"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"שגיאת VPN שמופעל תמיד"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"גע כדי לאפס את החיבור"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string>
     <string name="reset" msgid="2448168080964209908">"איפוס"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index fb7ceb9..df3d6f7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPNに常時接続しています…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPNに常時接続しました"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"常時接続VPNのエラー"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"接続をリセットするにはタップします"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
     <string name="reset" msgid="2448168080964209908">"リセット"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 53fbeb4..67192dd 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"연결 유지 VPN에 연결하는 중…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"연결 유지 VPN에 연결됨"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"연결 유지 VPN 오류"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"터치하여 연결 재설정"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string>
     <string name="reset" msgid="2448168080964209908">"초기화"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3b6e440..22656ff 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prisijungiama prie visada įjungto VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Prisijungta prie visada įjungto VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Visada įjungto VPN klaida"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Palieskite, kad iš naujo nustatytumėte ryšį"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string>
     <string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 646b7fa..f9b3381 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Notiek savienojuma izveide ar vienmēr ieslēgtu VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Izveidots savienojums ar vienmēr ieslēgtu VPN."</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kļūda saistībā ar vienmēr ieslēgtu VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Pieskarieties, lai atiestatītu savienojumu."</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string>
     <string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 784a424..d9b39aa 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sentiasa hidup sedang disambungkan..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sentiasa hidup telah disambungkan"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ralat VPN sentiasa hidup"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Sentuh untuk menetapkan semula sambungan"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string>
     <string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 485a11f8..4e7eba8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Alltid-på VPN kobler til ..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Alltid-på VPN er tilkoblet"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alltid-på VPN-feil"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Trykk for å tilbakestille tilkoblingen"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Velg fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
     <string name="reset" msgid="2448168080964209908">"Tilbakestill"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 95da93b..8af7e4c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN-verbinding maken…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN-verbinding"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fout met Always-on VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Raak dit aan om de verbinding opnieuw in te stellen"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Geen bestand geselecteerd"</string>
     <string name="reset" msgid="2448168080964209908">"Opnieuw instellen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f15c106..e7bee92 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Łączę z zawsze włączoną siecią VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Połączono z zawsze włączoną siecią VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Błąd zawsze włączonej sieci VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Kliknij, aby zresetować połączenie"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nie wybrano pliku"</string>
     <string name="reset" msgid="2448168080964209908">"Resetuj"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 7f7d6d2..552d24e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"A ligar VPN sempre ativa..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa ligada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro da VPN sempre ativa"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toque para repor a ligação"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string>
     <string name="reset" msgid="2448168080964209908">"Repor"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a2c6675..db894a0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toque para redefinir a conexão"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 53729f7..b49854a 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1993,7 +1993,7 @@
     <skip />
     <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
     <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
     <skip />
     <string name="upload_file" msgid="2897957172366730416">"Tscherner ina datoteca"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nagina datoteca tschernida"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e6d142b..fe7b437 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la reţeaua VPN activată permanent…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la reţeaua VPN activată permanent"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de reţea VPN activată permanent"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Atingeţi pentru a reseta conexiunea"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fişiere"</string>
     <string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fa623e0..249e46b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Подключение…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Подключено"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ошибка"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Нажмите, чтобы сбросить соединение"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
     <string name="reset" msgid="2448168080964209908">"Сбросить"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 5f49e68..e11f93a 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prebieha pripájanie k vždy zapnutej sieti VPN..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Pripojenie k vždy zapnutej sieti VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba vždy zapnutej siete VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dotykom obnovíte pripojenie"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string>
     <string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index aa240de..5a3f897 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Vzpostavljena povezava v stalno vklopljeno navidezno zasebno omrežje"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dotaknite se, da ponastavite povezavo"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string>
     <string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7a3ff07..2072c7e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Повезивање стално укљученог VPN-а..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Стално укључени VPN је повезан"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка стално укљученог VPN-а"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Додирните да бисте ресетовали везу"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
     <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index eca52e6..1b4cba5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ansluter till Always-on VPN ..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ansluten till Always-on VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fel på Always-on VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Tryck för att återställa anslutningen"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Välj fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil har valts"</string>
     <string name="reset" msgid="2448168080964209908">"Återställ"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 554921b..a678e1f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kila mara VPN iliyowashwa inaunganishwa…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Kila mara VPN iliyowashwa imeunganishwa"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kila mara kuna hitilafu ya VPN iliyowashwa"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Gusa ili kuweka upya muunganisho"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Chagua faili"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Hakuna faili iliyochaguliwa"</string>
     <string name="reset" msgid="2448168080964209908">"Weka upya"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index af28134..01a9fec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"กำลังเชื่อมต่อ VPN แบบเปิดตลอดเวลา…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"เชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"ข้อผิดพลาดของ VPN แบบเปิดตลอดเวลา"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"แตะเพื่อรีเซ็ตการเชื่อมต่อ"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string>
     <string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6268786..4de813a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kumukonekta ang Always-on VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Nakakonekta ang Always-on VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error sa Always-on VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Pindutin upang i-reset ang koneksyon"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string>
     <string name="reset" msgid="2448168080964209908">"I-reset"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 21fe6d4..cfc3c7b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Her zaman açık VPN\'ye bağlanılıyor…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Her zaman açık VPN\'ye bağlanıldı"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Her zaman açık VPN hatası"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Bağlantıyı sıfırlamak için dokunun"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string>
     <string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index ce5fdc06..095c364 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Під’єднання до постійної мережі VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Під’єднано до постійної мережі VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Помилка постійної мережі VPN"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Торкніться, щоб скинути з’єднання"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string>
     <string name="reset" msgid="2448168080964209908">"Віднов."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7edb530..2918928 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Đang kết nối VPN luôn bật…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Đã kết nối VPN luôn bật"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Lỗi VPN luôn bật"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Chạm để đặt lại kết nối"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string>
     <string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1406064..dcfc35f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在连接到始终开启的 VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已连接到始终开启的 VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"始终开启的 VPN 出现错误"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"触摸即可重置连接"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
     <string name="reset" msgid="2448168080964209908">"重置"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b313268..2ceb440 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"輕觸即可重設連線"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string>
     <string name="reset" msgid="2448168080964209908">"重設"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 30893c6..01cadb7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1269,7 +1269,8 @@
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"I-VPN ehlala ikhanya iyaxhuma…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"I-VPN ehlala ikhanya ixhunyiwe"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Iphutha le-VPN ehlala ikhanya"</string>
-    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Thinta ukuze usethe kabusha ukuxhuma"</string>
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
     <string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string>
     <string name="reset" msgid="2448168080964209908">"Setha kabusha"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 00c6f6d..5fc26fc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3512,8 +3512,8 @@
     <string name="vpn_lockdown_connected">Always-on VPN connected</string>
     <!-- Notification title when error connecting to lockdown VPN. -->
     <string name="vpn_lockdown_error">Always-on VPN error</string>
-    <!-- Notification body that indicates user can touch to cycle lockdown VPN connection. -->
-    <string name="vpn_lockdown_reset">Touch to reset connection</string>
+    <!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
+    <string name="vpn_lockdown_config">Touch to configure</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 412d4b9..c87cb27 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1487,6 +1487,9 @@
   <java-symbol type="anim" name="screen_user_exit" />
   <java-symbol type="anim" name="screen_user_enter" />
   <java-symbol type="anim" name="window_move_from_decor" />
+  <java-symbol type="anim" name="rotation_animation_jump_exit" />
+  <java-symbol type="anim" name="rotation_animation_xfade_exit" />
+  <java-symbol type="anim" name="rotation_animation_enter" />
   <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
@@ -1516,6 +1519,7 @@
   <java-symbol type="color" name="config_defaultNotificationColor" />
   <java-symbol type="drawable" name="ic_notification_ime_default" />
   <java-symbol type="drawable" name="ic_notify_wifidisplay" />
+  <java-symbol type="drawable" name="ic_menu_refresh" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled" />
   <java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -1649,7 +1653,7 @@
   <java-symbol type="string" name="vpn_lockdown_connecting" />
   <java-symbol type="string" name="vpn_lockdown_connected" />
   <java-symbol type="string" name="vpn_lockdown_error" />
-  <java-symbol type="string" name="vpn_lockdown_reset" />
+  <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
   <java-symbol type="string" name="wifi_display_notification_title" />
   <java-symbol type="string" name="wifi_display_notification_message" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 53876a5..e3c7cc4 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -167,7 +167,7 @@
                     ssidAppearInScanResultsCount, i));
             long startTime = System.currentTimeMillis();
             mAct.scanResultAvailable = false;
-            assertTrue("start scan failed", mAct.mWifiManager.startScanActive());
+            assertTrue("start scan failed", mAct.mWifiManager.startScan());
             while (true) {
                 if ((System.currentTimeMillis() - startTime) >
                 ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index d5fcc1c..dd60dd4 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -588,7 +588,7 @@
                 return true;
             } else {
                 // Start an active scan
-                mWifiManager.startScanActive();
+                mWifiManager.startScan();
                 mScanResultIsAvailable = false;
                 long startTime = System.currentTimeMillis();
                 while (!mScanResultIsAvailable) {
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 9519b9f..ebdbb0e 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -156,6 +156,8 @@
                 "Me: 16505551212 this\n",
                 "Me: 6505551212 this\n",
                 "Me: 5551212 this\n",
+                "Me: 2211 this\n",
+                "Me: 112 this\n",
 
                 "Me: 1-650-555-1212 this\n",
                 "Me: (650) 555-1212 this\n",
diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index b5fd88b..61b537d 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/html/about/versions/android-4.2.jd b/docs/html/about/versions/android-4.2.jd
index 13ee872..b02c1d1 100644
--- a/docs/html/about/versions/android-4.2.jd
+++ b/docs/html/about/versions/android-4.2.jd
@@ -111,6 +111,20 @@
 android:minSdkVersion}</a> is lower than 17, your app is not able to modify the settings that have
 moved to {@link android.provider.Settings.Global} when running on Android 4.2 and higher.</p>
   </li>
+
+  <li>If your app uses {@link android.webkit.WebView}, Android 4.2 adds an additional layer of
+  security so you can more safely <b>bind JavaScript to your
+  Android code</b>. If you set your
+  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+  to 17 or higher, you must now add the {@code @JavascriptInterface} annotation to any method that you
+  want available to your JavaScript (the method must also be public). If you do not provide the
+  annotation, the method is not accessible by a web page in your {@link android.webkit.WebView}
+  when running on Android 4.2 or higher. If you set the
+  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+  to 16 or lower, the annotation is not required, but we recommend that you update your target version
+  and add the annotation for additional security.
+    <p>Read more about <a href="{@docRoot}guide/webapps/webview.html#BindingJavaScript">binding
+    JavaScript code to Android code</a>.</p></li>
 </ul>
 
 
diff --git a/docs/html/distribute/googleplay/about/distribution.jd b/docs/html/distribute/googleplay/about/distribution.jd
index 746e180..78883b4 100644
--- a/docs/html/distribute/googleplay/about/distribution.jd
+++ b/docs/html/distribute/googleplay/about/distribution.jd
@@ -24,17 +24,18 @@
 automatic updates of your app, so that your updates are delivered and installed
 as soon as you publish them.</p>
 
+
 <h2 id="targeting">Reaching the customers you want</h2>
 
+<div class="figure-right" style="width:400px;">
+<img src="{@docRoot}images/gp-dc-countries.png" class="frame">
+</div>
+
 <p>Google Play does more than connect your app with users&mdash;it helps you
 reach the broadest possible distribution across the Android ecosystem, while
 making sure that your app is only available to the audience that you want to
 reach.</p>
 
-<div style="float:right;margin-left:18px;border:1px solid #DDD;margin:1.5em;">
-<img src="{@docRoot}images/gp-dc-countries.png" style="width:400px;padding:4px;margin-bottom:0;">
-</div>
-
 <h3 id="geotargeting">Geographic targeting</h3>
 
 <p>You can use controls in the Google Play Developer Console to easily
@@ -47,16 +48,15 @@
 and carrier targeting at any time just by saving changes in the Google Play
 Developer Console.</p>
 
+<div class="figure-right" style="width:400px;">
+<img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
+</div>
+
 <p>To help you market to users around the world, you
 can <a href="{@docRoot}distribute/googleplay/publish/preparing.html#localize">localize
 your store listing</a>, including app details and description,
 promotional graphics, screenshots, and more.</p>
 
-<div style="float:right;margin-left:18px;border:1px solid #DDD;margin:1.5em;">
-<img src="{@docRoot}images/gp-supported-dev-requirements.png"
-style="width:400px;padding:4px;margin-bottom:0;">
-</div>
-
 <h3 id="captargeting">Capabilities targeting</h3>
 
 <p>Google Play also lets you control distribution according to device features
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
index 8bafd53..8233a31 100644
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ b/docs/html/distribute/googleplay/about/monetizing.jd
@@ -116,8 +116,8 @@
 
 <h2 id="buyer-currency" style="margin-top:1.5em;">Flexible pricing in the currencies of your customers</h2>
 
-<div style="float:right;margin-left:18px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-buyer-currency.png" style="width:240px;padding:4px;margin-bottom:1em;">
+<div class="figure-right" style="width:250px;">
+<img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
 </div>
 
 <p>Google Play gives you complete control over how you price your products. You
diff --git a/docs/html/distribute/googleplay/publish/console.jd b/docs/html/distribute/googleplay/publish/console.jd
index cd1fd80..069b2d2 100644
--- a/docs/html/distribute/googleplay/publish/console.jd
+++ b/docs/html/distribute/googleplay/publish/console.jd
@@ -1,4 +1,4 @@
-page.title=The Developer Console
+page.title=Developer Console
 @jd:body
 
 
@@ -9,41 +9,40 @@
 tools on Google Play. This sections below introduce a few of the key areas
 you'll find in the Developer Console.</p>
 
-<div style="width:610px;margin-left:">
-<div style="width:610px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-home.png" style="width:600px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">All applications page</span>: Gives you a quick
+<div class="figure" style="width:756px;">
+<img src="{@docRoot}images/gp-dc-home.png" class="frame">
+<p class="img-caption"><strong>All applications page</strong>: Gives you a quick
 overview of your apps, lets you jump to stats, reviews, and product details, or
 upload a new app. </p>
 </div>
 
-
-<h3 id="profile">Your Account Details</h3>
-
-<div style="width:408px;float:right;margin:1.5em;">
-<div style="width:410px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-profile.png" style="width:400px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Account details page</span>: Specifies your developer
+<div class="figure-right" style="width:450px;">
+<img src="{@docRoot}images/gp-dc-profile.png" class="frame">
+<p class="img-caption"><strong>Account details page</strong>: Specifies your developer
 identity and contact information, accounts for app testing, and more.</p>
 </div>
 
-<p>Your developer profile identifies you to Google Play and to your customers.
-During registration you must provide information for your profile, but you can go
-back at any time to edit the information and change your settings. </p>
+<h3 id="profile">Your account details</h3>
+
+<p>The account details page is where you specify basic information about yourself
+or your company in a developer profile. The information in your developer profile
+is important because it identifies you to Google Play and also to your customers.</p>
+
+<p>During registration you must provide the information for your profile, but you can
+go back at any time to edit the information and change your settings. </p>
 
 <p>Your developer profile contains:</p>
 <ul>
-<li>Your developer name &mdash; the name you want to show users on your product
-details page and elsewhere on Google Play. 
+<li>Your developer name &mdash; the name you want to show users on your store
+listing page and elsewhere on Google Play. </li>
 <li>Your developer contact information &mdash; how Google can contact you if
-needed (this information isn't exposed to users).
-<li>Merchant information, in-app billing information.</li>
+needed (this information isn't exposed to users).</li>
+<li>Your developer website URL &mdash; shown to users on your store listing page
+so they can learn more about your company or products.</li>
 </ul>
 
+<p>On the account details page you can also register for a merchant account, set
+up test accounts for Google Play licensing, and more. </p>
 
 <h3 id="user-accounts">Multiple user accounts</h3>
 
@@ -55,6 +54,13 @@
 app configuration, but not access to financial reports. </p>
 
 
+<div class="figure-right" style="width:450px;">
+<img src="{@docRoot}images/gp-dc-details.png" class="frame">
+<p class="img-caption"><strong>Store listing page</strong>: Lets you upload your
+graphic assets, description, support information, and other information to
+create the store listing page for a specific app.</p>
+</div>
+
 <h3 id="merchant">Linking your Merchant Account</h3>
 
 <p>If you want to sell apps or in-app products, you can link your Google
@@ -62,17 +68,6 @@
 Checkout account for financial and tax identification and monthly payouts of
 sales. </p>
 
-<div style="width:410px;float:right;margin:1.5em;">
-<div style="width:410px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-details.png" style="width:400px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Store Listing page</span>: Lets you upload your
-graphic assets, description, support information, and other information to
-create the product details page for a specific app.</p>
-</div>
-
-
 <h3 id="details">Your store listing details</h3>
 
 <p>The Developer Console lets you set up a colorful storefront page for your app
@@ -86,15 +81,14 @@
 notes about the latest version, and more. You can update your store listing at
 any time, even if you don’t have a new version of your application.</p>
 
-
 <h3 id="uploading">Uploading and publishing</h3>
 
 <p>From the Developer Console you can quickly upload a release-ready APK and
 publish it when you're ready. The app is a <em>draft</em> until you publish it,
-at which time Google Play makes your store listing and app available to
+at which time Google Play makes your store listing page and app available to
 users. You can unpublish the app at any time.</p>
 
-<h3 id="controls">Distribution Controls</h3>
+<h3 id="controls">Distribution controls</h3>
 
 <p>In the Developer Console you can manage what countries and territories the
 app is distributed to and, for some countries, you can choose what carriers you
@@ -103,8 +97,7 @@
 <p>You can also see the list of devices that your app is currently available to,
 based on any distribution rules declared in its manifest file.</p>
 
-
-<h3 id="profile">Selling and pricing your Products</h3>
+<h3 id="selling">Selling and pricing your products</h3>
 
 <p>The Developer Console gives you tools to set prices for your apps and in-app
 products. Your app can either be free to download or priced (charged before
@@ -149,17 +142,18 @@
 <a href="{@docRoot}google/play/billing/index.html">In-app Billing</span></a>
 developer documentation.</p></div></div>
 
-<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is a Google Play service that lets you monetize your apps in more ways by selling in-app products and subscriptions. In-app products are one-time purchases, while  subscriptions are recurring charges on an monthly or annual basis.</p>
+<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is
+a Google Play service that lets you monetize your apps in more ways by selling
+in-app products and subscriptions. In-app products are one-time purchases, while
+subscriptions are recurring charges on an monthly or annual basis.</p>
 
 <p>From the Developer Console you can create product lists for in-app
 products and subscriptions, set prices, and publish.</p>
 
-<div style="width:410px;float:right;margin:1.5em;">
-<div style="width:410px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-reviews.png" style="width:400px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span style="font-weight:500;">User
-reviews page</span>: Gives you access to user reviews for a specific app.
+<div class="figure-right" style="width:410px;">
+<img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
+<p class="img-caption"><strong>User
+reviews page</strong>: Gives you access to user reviews for a specific app.
 You can filter  reviews in a number of ways to locate issues more easily
 and support your customers more effectively.</p>
 </div>
@@ -182,7 +176,7 @@
 
 <p>You can view installations of your app measured by unique users, as well as
 by unique devices. For user installations, you can view active installs, total
-installs, daily installs and uninstalls, and metrics about the user reviews.
+installs, daily installs and uninstalls, and metrics about user ratings.
 For devices, you can see active
 installs as well as daily installs, uninstalls, and upgrades.</p>
 
@@ -197,12 +191,8 @@
 specific points (such as individual platform versions or languages) to the
 timeline.</p>
 
-<div style="width:610px;margin:1.5em;margin-left:0">
-<div style="width:610px;border:1px solid #DDD;">
-<img src="{@docRoot}images/gp-dc-stats.png" 
-style="width:600px;padding:4px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span style="font-weight:500;">App
-statistics page</span>: Shows you a variety of statistics about a
-specific app's installation performance over time.</p>
+<div style="width:530px;">
+<img src="{@docRoot}images/gp-dc-stats.png" class="frame">
+<p class="img-caption"><strong>App statistics page</strong>: Shows you a variety
+of statistics about a specific app's installation performance over time.</p>
 </div>
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 406d412..0925f3c 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -422,8 +422,8 @@
 started on creating them and localizing them well in advance of your target
 publishing date. </p>
 
-<p class="note"><strong>Note:</strong> Localized promotional graphics and videos are supported
-only in the new Developer Console design.</p>
+<p class="note"><strong>Note:</strong> Localized promotional graphics and videos
+are supported only in the new Developer Console design.</p>
 
 <table>
 <tr>
@@ -547,7 +547,7 @@
 <h2 id="final-checks">16. Final checks and publishing</h2> 
 
 <p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
-final checks:</p>
+final checks.</p>
 
 <p>Make sure that: </p>
 
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index cfa7a30..91883da1 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -492,7 +492,7 @@
 <div style="margin:1em;">
 <img style="border:1px solid #ddd;padding-bottom:.5em" src="{@docRoot}images/in-app-billing/billing_app_key.png" xheight="510" id="figure4" />
 <p class="img-caption" style="padding-left:.5em;">
-  <strong>Figure 4.</strong> You can find the license key for each app in the <strong>Services & APIs</strong> panel.
+  <strong>Figure 4.</strong> You can find the license key for each app in the <strong>Services &amp; APIs</strong> panel.
 </p>
 </div>
 
diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd
index 7b748a3..c065ffb 100755
--- a/docs/html/google/play/billing/v2/billing_integrate.jd
+++ b/docs/html/google/play/billing/v2/billing_integrate.jd
@@ -170,15 +170,14 @@
 following:</p>
 
 <ol>
-  <li><strong>Add your Google Play public key to the sample application code.</strong>
+  <li><strong>Add your app's public key to the sample application code.</strong>
     <p>This enables the application to verify the signature of the transaction information that is
     returned from Google Play. To add your public key to the sample application code, do the
     following:</p>
     <ol>
-      <li>Log in to your Google Play <a href="http://play.google.com/apps/publish">publisher
-      account</a>.</li>
-      <li>On the upper left part of the page, under your name, click <strong>Edit
-      Profile</strong>.</li>
+      <li>Log in to your Google Play <a href="http://play.google.com/apps/publish">Developer
+      console</a>.</li>
+      <li>On the upper left part of the page, All Applications, click the application name.</strong>.</li>
       <li>On the Edit Profile page, scroll down to the <strong>Licensing &amp; In-app
       Billing</strong> panel.</li>
       <li>Copy your public key.</li>
@@ -512,7 +511,7 @@
 three keys that are required for all requests: <code>BILLING_REQUEST</code>,
 <code>API_VERSION</code>, and <code>PACKAGE_NAME</code>. If you are offering subscriptions in
 your app, set the API_VERSION key to a value of "2", to confirm that In-app Billing v2 is
-available. For an examnple, see
+available. For an example, see
 <a href="{@docRoot}google/play/billing/v2/billing_subscriptions.html#version">Subscriptions</a>.</p>
 
 <p>The <code>CHECK_BILLING_SUPPORTED</code> request returns a synchronous {@link
@@ -1044,14 +1043,14 @@
 
 <p>You will need to use your Google Play public key to perform the signature verification. The
 following procedure shows you how to retrieve Base64-encoded public key from the Google Play
-publisher site.</p>
+Developer Console.</p>
 
 <ol>
   <li>Log in to your <a href="http://play.google.com/apps/publish">publisher account</a>.</li>
-  <li>On the upper left part of the page, under your name, click <strong>Edit profile</strong>.</li>
-  <li>On the Edit Profile page, scroll down to the Licensing &amp; In-app Billing panel (see figure
-  2).</li>
-  <li>Copy your public key.</li>
+  <li>On the upper left part of the page, click <strong>All applications</strong> and then click
+  the app name in the listing.</li>
+  <li>Click <em>Services &amp; APIs</em> and find "Your License Key for this Application" on the page. </li>
+  <li>Copy the app's public key.</li>
 </ol>
 
 <p class="caution"><strong>Important</strong>: To keep your public key safe from malicious users and
@@ -1060,11 +1059,13 @@
 actual key. The key itself is not secret information, but you do not want to make it easy for a
 hacker or malicious user to replace the public key with another key.</p>
 
-<img src="{@docRoot}images/billing_public_key.png" height="510" id="figure2" />
-<p class="img-caption">
-  <strong>Figure 2.</strong> The Licensing and In-app Billing panel of your account's Edit Profile
-  page lets you see your public key.
-</p>
+<div style="width:640px;">
+<img src="{@docRoot}images/licensing_public_key.png" class="frame">
+<p class="img-caption"><strong>Figure
+2.</strong> An app's license key is available from the Services &amp; APIs page in
+the Developer Console.</p>
+</div>
+
 
 <h2 id="billing-implement">Modifying Your Application Code</h2>
 
diff --git a/docs/html/google/play/licensing/setting-up.jd b/docs/html/google/play/licensing/setting-up.jd
index 1d4e775..d83f91b 100644
--- a/docs/html/google/play/licensing/setting-up.jd
+++ b/docs/html/google/play/licensing/setting-up.jd
@@ -32,29 +32,25 @@
 </div>
 
 <p>Before you start adding license verification to your application, you need to set up your Google
-Play publishing account, your development environment, and test accounts required to verify
+Play publishing account, your development environment, and any test accounts required to verify
 your implementation.</p>
 
 
 <h2 id="account">Setting Up a Publisher Account</h2>
 
 <p>If you don't already have a publisher account for Google Play, you need to register for one
-using your Google account and agree to the terms of service on the Google Play publisher site:</p>
-
-<p style="margin-left:2em;"><a
-href="http://play.google.com/apps/publish">http://play.google.com/apps/publish</a>
-</p>
+using your Google account and agree to the Google Play terms of service.</p>
 
 <p>For more information, see <a
 href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with Publishing</a>.</p>
 
-<p>If you already have a publisher account on Google Play, use your existing
-account to set up licensing.</p>
+<p>If you already have a publisher account on Google Play, use your
+Developer Console to set up licensing.</p>
 
-<p>Using your publisher account on Google Play, you can:</p>
+<p>Using the Google Play Developer Console, you can:</p>
 
 <ul>
-<li>Obtain a public key for licensing</li>
+<li>Obtain an app-specific public key for licensing</li>
 <li>Debug and test an application's licensing implementation, prior to
 publishing the application</li>
 <li>Publish the applications to which you have added licensing support</li>
@@ -63,33 +59,35 @@
 <h4>Administrative settings for licensing</h4>
 
 <p>You can manage several
-administrative controls for Google Play licensing on the publisher site. The controls are available
-in the Edit Profile page, in the "Licensing" panel, shown in figure 1. The controls
+administrative controls for Google Play licensing in the Developer Console. The controls
 let you: </p>
 
 <ul>
 <li>Set up multiple "test accounts," identified by email address. The licensing
 server allows users signed in to test accounts on a device or emulator to send
-license checks and receive static test responses.</li>
-<li>Obtain the account's public key for licensing. When you are implementing
-licensing in an application, you must copy the public key string into the
-application.</li>
+license checks and receive static test responses. You can set up accounts in the
+Account Details page of the Developer Console.</li>
 <li>Configure static test responses that the server sends, when it receives a
 license check for an application uploaded to the publisher account, from a user
-signed in to the publisher account or a test account.</li>
+signed in to the publisher account or a test account. You can set test responses
+in the Account Details page of the Developer Console.</li>
+<li>Obtain the app's public key for licensing. When you are implementing
+licensing in an application, you must copy the public key string into the
+application. You can obtain the app's public key for licensing in the Services
+& APIs page (under All Applications).</li>
 </ul>
 
-
-<img src="{@docRoot}images/licensing_public_key.png" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> The Licensing
-panel of your account's Edit Profile page lets you manage administrative
-settings for licensing.</p>
+<div style="width:640px;">
+<img src="{@docRoot}images/licensing_public_key.png" class="frame">
+<p class="img-caption"><strong>Figure
+2.</strong> An app's license key is available from the Services &amp; APIs page in
+the Developer Console.</p>
+</div>
 
 <p>For more information about how to work with test accounts and static test
 responses, see <a href="#test-env">Setting Up a Testing Environment</a>, below.
 
 
-
 <h2 id="dev-setup">Setting Up the Development Environment</h2>
 
 <p>Setting up your environment for licensing involves these tasks:</p>
@@ -432,9 +430,9 @@
 
 <h2 id="test-env">Setting Up the Testing Environment</h2>
 
-<p>The Google Play publisher site provides configuration tools that let you
+<p>The Google Play Developer Console provides configuration tools that let you
 and others test licensing on your application before it is published. As you are
-implementing licensing, you can make use of the publisher site tools to test
+implementing licensing, you can make use of the Developer Console tools to test
 your application's Policy and handling of different licensing responses and
 error conditions.</p>
 
@@ -487,10 +485,12 @@
 Response Codes</a> in the <a
 href="{@docRoot}google/play/licensing/licensing-reference.html">Licensing Reference</a>.</p>
 
-<img src="{@docRoot}images/licensing_test_response.png" alt=""/>
-<p class="img-caption"><strong>Figure 4.</strong> The Licensing
-panel of your account's Edit Profile page, showing the Test Accounts field and the
-Test Response menu.</p>
+<div style="width:640px;">
+<img src="{@docRoot}images/licensing_test_response.png" class="frame">
+<p class="img-caption"><strong>Figure 4.</strong> The License Testing
+panel of your Account details page lets you set up test accounts and
+manage test responses.</p>
+</div>
 
 <p>Note that the test response that you configure applies account-wide &mdash;
 that is, it applies not to a single application, but to <em>all</em>
@@ -516,7 +516,7 @@
 <p>In some cases, you might want to let multiple teams of developers test
 licensing on applications that will ultimately be published through your
 publisher account, but without giving them access to your publisher account's
-sign-in credentials. To meet that need, the Google Play publisher site lets
+sign-in credentials. To meet that need, the Google Play Developer Console lets
 you set up one or more optional <em>test accounts</em> &mdash; accounts that are
 authorized to query the licensing server and receive static test responses from
 your publisher account.</p>
@@ -609,13 +609,13 @@
 
 <p>The licensing server handles static test responses in the normal way,
 including signing the license response data, adding extras parameters, and so
-on. To support developers who are implementing licensing using test accounts,
+on. To support developers who are implementing licensing using test accounts
 rather than the publisher account, you will need to distribute
-your public key to them. Developers without access to the publisher site do not
-have access to your public key, and without the key they won't be able to
-verify license responses. </p>
+the app's public key for licensing to them. Developers without access to the
+Developer Console do not have access to the app's public key, and without
+the key they won't be able to verify license responses. </p>
 
-<p>Note that if you decide to generate a new licensing key pair for your account
+<p>Note that if you decide to generate a new licensing key pair for the app
 for some reason, you need to notify all users of test accounts. For
 testers, you can embed the new key in the application package and distribute it
 to users. For developers, you will need to distribute the new key to them
@@ -661,7 +661,7 @@
 
 <p>Signing in using a publisher account offers the advantage of letting your
 applications receive static test responses even before the applications are
-uploaded to the publisher site.</p>
+uploaded to the Developer Console.</p>
 
 <p>If you are part of a larger organization or are working with external groups
 on applications that will be published through your site, you will more likely
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index f9e2785..3b3bb8f 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -26,14 +26,14 @@
 </div>
 </div>
 
-<div class="sidebox-wrapper"> 
+<div class="sidebox-wrapper">
 <div class="sidebox">
-    <img src="{@docRoot}assets/images/icon_play.png" style="float:left;margin:0;padding:0;"> 
-    <p style="color:#669999;padding-top:1em;">Google Play Filtering</p> 
+    <img src="{@docRoot}assets/images/icon_play.png" style="float:left;margin:0;padding:0;">
+    <p style="color:#669999;padding-top:1em;">Google Play Filtering</p>
     <p style="padding-top:1em;">Google Play uses the <code>&lt;uses-sdk&gt;</code>
-    attributes declared in your app manifest to filter your app from devices 
+    attributes declared in your app manifest to filter your app from devices
     that do not meet it's platform version requirements. Before setting these
-    attributes, make sure that you understand 
+    attributes, make sure that you understand
     <a href="{@docRoot}google/play/filters.html">Google Play filters</a>. </p>
   </div>
 </div>
@@ -41,7 +41,7 @@
 <dl class="xml">
 <dt>syntax:</dt>
 <dd><pre>
-&lt;uses-sdk android:<a href="#min">minSdkVersion</a>="<i>integer</i>" 
+&lt;uses-sdk android:<a href="#min">minSdkVersion</a>="<i>integer</i>"
           android:<a href="#target">targetSdkVersion</a>="<i>integer</i>"
           android:<a href="#max">maxSdkVersion</a>="<i>integer</i>" /&gt;</pre></dd>
 
@@ -55,14 +55,14 @@
 </p>
 
 <p>Despite its name, this element is used to specify the API Level, <em>not</em>
-the version number of the SDK (software development kit) or Android platform. 
+the version number of the SDK (software development kit) or Android platform.
 The API Level is always a single integer. You cannot derive the API Level from
 its associated Android version number (for example, it is not the same as the
 major version or the sum of the major and minor versions).</p>
 
 <p>Also read the document about
 <a href="{@docRoot}tools/publishing/versioning.html">Versioning Your Applications</a>.
-</p></dd> 
+</p></dd>
 
 <dt>attributes:</dt>
 
@@ -117,8 +117,8 @@
   </dd>
 
   <dt><a name="max"></a>{@code android:maxSdkVersion}</dt>
-  <dd>An integer designating the maximum API Level on which the application is 
-  designed to run. 
+  <dd>An integer designating the maximum API Level on which the application is
+  designed to run.
 
   <p>In Android 1.5, 1.6, 2.0, and 2.0.1, the system checks the value of this
   attribute when installing an application and when re-validating the application
@@ -165,7 +165,7 @@
 as a filter, however, when presenting users with applications available for
 download. </div>
   </dd>
-  
+
 
 </dl></dd>
 
@@ -217,7 +217,7 @@
 <p>The framework API that an Android platform delivers is specified using an
 integer identifier called "API Level". Each Android platform version supports
 exactly one API Level, although support is implicit for all earlier API Levels
-(down to API Level 1). The initial release of the Android platform provided 
+(down to API Level 1). The initial release of the Android platform provided
 API Level 1 and subsequent releases have incremented the API Level.</p>
 
 <p>The table below specifies the API Level supported by each version of the
@@ -227,8 +227,8 @@
 
 <table>
   <tr><th>Platform Version</th><th>API Level</th><th>VERSION_CODE</th><th>Notes</th></tr>
- 
-    <tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2</a></td>
+
+    <tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2, 4.2.2</a></td>
     <td><a href="{@docRoot}sdk/api_diff/17/changes.html" title="Diff Report">17</a></td>
     <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}</td>
     <td><a href="{@docRoot}about/versions/jelly-bean.html">Platform
@@ -250,70 +250,70 @@
     <td><a href="{@docRoot}sdk/api_diff/14/changes.html" title="Diff Report">14</a></td>
     <td>{@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}</td>
     </tr>
-  
+
     <tr><td><a href="{@docRoot}about/versions/android-3.2.html">Android 3.2</a></td>
     <td><a href="{@docRoot}sdk/api_diff/13/changes.html" title="Diff Report">13</a></td>
     <td>{@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}</td>
     <td><!-- <a href="{@docRoot}about/versions/android-3.2-highlights.html">Platform
 Highlights</a>--></td></tr>
-  
+
   <tr><td><a href="{@docRoot}about/versions/android-3.1.html">Android 3.1.x</a></td>
     <td><a href="{@docRoot}sdk/api_diff/12/changes.html" title="Diff Report">12</a></td>
     <td>{@link android.os.Build.VERSION_CODES#HONEYCOMB_MR1}</td>
     <td><a href="{@docRoot}about/versions/android-3.1-highlights.html">Platform Highlights</a></td></tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-3.0.html">Android 3.0.x</td>
     <td><a href="{@docRoot}sdk/api_diff/11/changes.html" title="Diff Report">11</a></td>
     <td>{@link android.os.Build.VERSION_CODES#HONEYCOMB}</td>
     <td><a href="{@docRoot}about/versions/android-3.0-highlights.html">Platform Highlights</a></td></tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-2.3.3.html">Android 2.3.4<br>Android 2.3.3</td>
     <td><a href="{@docRoot}sdk/api_diff/10/changes.html" title="Diff Report">10</a></td>
     <td>{@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1}</td>
     <td rowspan="2"><a href="{@docRoot}about/versions/android-2.3-highlights.html">Platform
 Highlights</a></td></tr>
-  
+
   <tr><td><a href="{@docRoot}about/versions/android-2.3.html">Android 2.3.2<br>Android 2.3.1<br>Android
 2.3</td>
     <td><a href="{@docRoot}sdk/api_diff/9/changes.html" title="Diff Report">9</a></td>
     <td>{@link android.os.Build.VERSION_CODES#GINGERBREAD}</td>
     </tr>
-  
+
   <tr><td><a href="{@docRoot}about/versions/android-2.2.html">Android 2.2.x</td>
     <td ><a href="{@docRoot}sdk/api_diff/8/changes.html" title="Diff Report">8</a></td>
     <td>{@link android.os.Build.VERSION_CODES#FROYO}</td>
     <td><a href="{@docRoot}about/versions/android-2.2-highlights.html">Platform Highlights</a></td></tr>
-  
+
   <tr><td><a href="{@docRoot}about/versions/android-2.1.html">Android 2.1.x</td>
     <td><a href="{@docRoot}sdk/api_diff/7/changes.html" title="Diff Report">7</a></td>
     <td>{@link android.os.Build.VERSION_CODES#ECLAIR_MR1}</td>
     <td rowspan="3" ><a href="{@docRoot}about/versions/android-2.0-highlights.html">Platform
 Highlights</a></td></tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-2.0.1.html">Android 2.0.1</td>
     <td><a href="{@docRoot}sdk/api_diff/6/changes.html" title="Diff Report">6</a></td>
     <td>{@link android.os.Build.VERSION_CODES#ECLAIR_0_1}</td>
     </tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-2.0.html">Android 2.0</td>
     <td><a href="{@docRoot}sdk/api_diff/5/changes.html" title="Diff Report">5</a></td>
     <td>{@link android.os.Build.VERSION_CODES#ECLAIR}</td>
     </tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-1.6.html">Android 1.6</td>
     <td><a href="{@docRoot}sdk/api_diff/4/changes.html" title="Diff Report">4</a></td>
     <td>{@link android.os.Build.VERSION_CODES#DONUT}</td>
     <td><a href="{@docRoot}about/versions/android-1.6-highlights.html">Platform Highlights</a></td></tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-1.5.html">Android 1.5</td>
     <td><a href="{@docRoot}sdk/api_diff/3/changes.html" title="Diff Report">3</a></td>
     <td>{@link android.os.Build.VERSION_CODES#CUPCAKE}</td>
     <td><a href="{@docRoot}about/versions/android-1.5-highlights.html">Platform Highlights</a></td></tr>
-    
+
   <tr><td><a href="{@docRoot}about/versions/android-1.1.html">Android 1.1</td>
     <td>2</td>
     <td>{@link android.os.Build.VERSION_CODES#BASE_1_1}</td><td></td></tr>
-    
+
   <tr><td>Android 1.0</td>
     <td>1</td>
     <td>{@link android.os.Build.VERSION_CODES#BASE}</td>
@@ -324,10 +324,10 @@
 <h2 id="uses">Uses of API Level in Android</h2>
 
 <p>The API Level identifier serves a key role in ensuring the best possible
-experience for users and application developers: 
+experience for users and application developers:
 
 <ul>
-<li>It lets the Android platform describe the maximum framework API revision 
+<li>It lets the Android platform describe the maximum framework API revision
 that it supports</li>
 <li>It lets applications describe the framework API revision that they
 require</li>
@@ -349,7 +349,7 @@
 <li><code>android:targetSdkVersion</code> &mdash; Specifies the API Level
 on which the application is designed to run. In some cases, this allows the
 application to use manifest elements or behaviors defined in the target
-API Level, rather than being restricted to using only those defined 
+API Level, rather than being restricted to using only those defined
 for the minimum API Level.</li>
 <li><code>android:maxSdkVersion</code> &mdash; Specifies the maximum API Level
 on which the application is able to run. <strong>Important:</strong> Please read the <a
@@ -375,7 +375,7 @@
 must be less than or equal to the system's API Level integer. If not declared,
 the system assumes that the application requires API Level 1. </li>
 <li>If a <code>android:maxSdkVersion</code> attribute is declared, its value
-must be equal to or greater than the system's API Level integer. 
+must be equal to or greater than the system's API Level integer.
 If not declared, the system assumes that the application
 has no maximum API Level. Please read the <a
 href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
@@ -470,7 +470,7 @@
 <p>When you are developing your application, you will need to choose
 the platform version against which you will compile the application. In
 general, you should compile your application against the lowest possible
-version of the platform that your application can support. 
+version of the platform that your application can support.
 
 <p>You can determine the lowest possible platform version by compiling the
 application against successively lower build targets. After you determine the
@@ -513,7 +513,7 @@
 located in the &lt;sdk&gt;/tools directory. You can launch the SDK updater by
 executing <code>android sdk</code>. You can
 also simply double-click the android.bat (Windows) or android (OS X/Linux) file.
-In ADT, you can also access the updater by selecting 
+In ADT, you can also access the updater by selecting
 <strong>Window</strong>&nbsp;>&nbsp;<strong>Android SDK
 Manager</strong>.</p>
 
@@ -552,9 +552,9 @@
 <h2 id="filtering">Filtering the Reference Documentation by API Level</h2>
 
 <p>Reference documentation pages on the Android Developers site offer a "Filter
-by API Level" control in the top-right area of each page. You can use the 
-control to show documentation only for parts of the API that are actually 
-accessible to your application, based on the API Level that it specifies in 
+by API Level" control in the top-right area of each page. You can use the
+control to show documentation only for parts of the API that are actually
+accessible to your application, based on the API Level that it specifies in
 the <code>android:minSdkVersion</code> attribute of its manifest file. </p>
 
 <p>To use filtering, select the checkbox to enable filtering, just below the
@@ -574,10 +574,10 @@
 </p>
 
 <p>Also note that the reference documentation for individual API elements
-specifies the API Level at which each element was introduced. The API Level 
-for packages and classes is specified as "Since &lt;api level&gt;" at the 
-top-right corner of the content area on each documentation page. The API Level 
-for class members is specified in their detailed description headers, 
+specifies the API Level at which each element was introduced. The API Level
+for packages and classes is specified as "Since &lt;api level&gt;" at the
+top-right corner of the content area on each documentation page. The API Level
+for class members is specified in their detailed description headers,
 at the right margin. </p>
 
 
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 4a4b1d5..05ec279 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -355,7 +355,7 @@
         new NotificationCompat.InboxStyle();
 String[] events = new String[6];
 // Sets a title for the Inbox style big view
-inboxStyle.SetBigContentTitle("Event tracker details:");
+inboxStyle.setBigContentTitle("Event tracker details:");
 ...
 // Moves events into the big view
 for (int i=0; i &lt; events.length; i++) {
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index f8b2a1d..d2b2532 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -178,8 +178,8 @@
 href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
 to 17 or higher, <strong>you
 must add the {@code &#64;JavascriptInterface} annotation</strong> to any method that you want
-available your web page code (the method must also be public). If you do not provide the
-annotation, then the method will not accessible by your web page when running on Android 4.2 or
+available to your JavaScript (the method must also be public). If you do not provide the
+annotation, the method is not accessible by your web page when running on Android 4.2 or
 higher.</p>
 
 <p>In this example, the {@code WebAppInterface} class allows the web page to create a {@link
diff --git a/docs/html/images/billing_public_key.png b/docs/html/images/billing_public_key.png
deleted file mode 100644
index a0620f8..0000000
--- a/docs/html/images/billing_public_key.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-buyer-currency.png b/docs/html/images/gp-buyer-currency.png
index 51b8108..96d7e65 100644
--- a/docs/html/images/gp-buyer-currency.png
+++ b/docs/html/images/gp-buyer-currency.png
Binary files differ
diff --git a/docs/html/images/gp-dc-countries.png b/docs/html/images/gp-dc-countries.png
index 00d0d5e..72ce796 100644
--- a/docs/html/images/gp-dc-countries.png
+++ b/docs/html/images/gp-dc-countries.png
Binary files differ
diff --git a/docs/html/images/gp-dc-details.png b/docs/html/images/gp-dc-details.png
index 567567e..5b7eba4 100644
--- a/docs/html/images/gp-dc-details.png
+++ b/docs/html/images/gp-dc-details.png
Binary files differ
diff --git a/docs/html/images/gp-dc-home.png b/docs/html/images/gp-dc-home.png
index 381d0db..5ed46c9 100644
--- a/docs/html/images/gp-dc-home.png
+++ b/docs/html/images/gp-dc-home.png
Binary files differ
diff --git a/docs/html/images/gp-dc-profile.png b/docs/html/images/gp-dc-profile.png
index e526369..e254e5d 100644
--- a/docs/html/images/gp-dc-profile.png
+++ b/docs/html/images/gp-dc-profile.png
Binary files differ
diff --git a/docs/html/images/gp-dc-reviews.png b/docs/html/images/gp-dc-reviews.png
index cab175a..4290136 100644
--- a/docs/html/images/gp-dc-reviews.png
+++ b/docs/html/images/gp-dc-reviews.png
Binary files differ
diff --git a/docs/html/images/gp-dc-stats-mini.png b/docs/html/images/gp-dc-stats-mini.png
index d29a270..211b5ea 100644
--- a/docs/html/images/gp-dc-stats-mini.png
+++ b/docs/html/images/gp-dc-stats-mini.png
Binary files differ
diff --git a/docs/html/images/gp-dc-stats.png b/docs/html/images/gp-dc-stats.png
index 06f88e5..7df6266 100644
--- a/docs/html/images/gp-dc-stats.png
+++ b/docs/html/images/gp-dc-stats.png
Binary files differ
diff --git a/docs/html/images/gp-devconsole-home.png b/docs/html/images/gp-devconsole-home.png
index 1d758fd..b29dc25 100644
--- a/docs/html/images/gp-devconsole-home.png
+++ b/docs/html/images/gp-devconsole-home.png
Binary files differ
diff --git a/docs/html/images/gp-supported-dev-requirements.png b/docs/html/images/gp-supported-dev-requirements.png
index d84f34e..c38b8aa 100644
--- a/docs/html/images/gp-supported-dev-requirements.png
+++ b/docs/html/images/gp-supported-dev-requirements.png
Binary files differ
diff --git a/docs/html/images/home/io-logo-2013.png b/docs/html/images/home/io-logo-2013.png
new file mode 100644
index 0000000..c95719e
--- /dev/null
+++ b/docs/html/images/home/io-logo-2013.png
Binary files differ
diff --git a/docs/html/images/licensing_public_key.png b/docs/html/images/licensing_public_key.png
index 1630209..a3cd785 100644
--- a/docs/html/images/licensing_public_key.png
+++ b/docs/html/images/licensing_public_key.png
Binary files differ
diff --git a/docs/html/images/licensing_test_response.png b/docs/html/images/licensing_test_response.png
index ead2152..219ae24 100644
--- a/docs/html/images/licensing_test_response.png
+++ b/docs/html/images/licensing_test_response.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index afda7a9..a0029b5 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -13,6 +13,21 @@
         <div class="frame">
             <ul>
                 <li class="item carousel-home">
+                    <div class="content-left col-10">
+                    <img src="{@docRoot}images/home/io-logo-2013.png" style="margin:40px 0 0">
+                    </div>
+                    <div class="content-right col-5">
+                    <h1>Google I/O 2013</h1>
+                    <p>Android will be at Google I/O on May 15-17, 2013, with sessions covering a variety of topics
+                    such as design, performance, and how to extend your app with the latest Android features.
+                    Registration opens on March 13, 2013 at 7:00 AM PDT (GMT-7).</p>
+                    <p>For more information about event details and planned sessions,
+                    stay tuned to <a
+                    href="http://google.com/+GoogleDevelopers">+Google Developers</a>.</p>
+                    <p><a href="https://developers.google.com/events/io/" class="button">Register here</a></p>
+                    </div>
+                </li>
+                <li class="item carousel-home">
                     <div class="content-left col-11" style="padding-top:65px;">
                       <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
                       <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:338px">
@@ -80,18 +95,6 @@
                 </li>
                 <li class="item carousel-home">
                         <div class="content-left col-10">
-                        <img src="{@docRoot}images/home/google-io.png">
-                        </div>
-                        <div class="content-right col-5">
-                        <h1>Android videos<br/> from Google I/O!</h1>
-                        <p>If you couldn't make it to Google I/O this year or want to review some of the material,
-                          all of the Android sessions are now available for viewing online.</p>
-                        <p><a href="http://www.youtube.com/playlist?list=PL4C6BCDE45E05F49E&feature=plcp"
-class="button">Watch the Android sessions</a></p>
-                        </div>
-                </li>
-                <li class="item carousel-home">
-                        <div class="content-left col-10">
                             <img src="{@docRoot}images/home/google-play.png"
                                   style="margin-top:50px">
                         </div>
diff --git a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
index 8ff9fec..f07adfd 100644
--- a/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
+++ b/docs/html/reference/com/google/android/gms/common/GooglePlayServicesClient.html
@@ -687,9 +687,7 @@
             
               <a href="/reference/com/google/android/gms/panorama/PanoramaClient.html">PanoramaClient</a>,
             
-              <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a>,
-            
-              <a href="/reference/com/google/android/gms/wallet/WalletClient.html">WalletClient</a>
+              <a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a>
             
           
       </div>
@@ -705,10 +703,6 @@
               <td class="jd-linkcol"><a href="/reference/com/google/android/gms/plus/PlusClient.html">PlusClient</a></td>
               <td class="jd-descrcol" width="100%">The main entry point for Google+ integration.&nbsp;</td>
           </tr>
-        <tr class="alt-color api apilevel-" >
-              <td class="jd-linkcol"><a href="/reference/com/google/android/gms/wallet/WalletClient.html">WalletClient</a></td>
-              <td class="jd-descrcol" width="100%">The main entry point for Google Wallet integration.&nbsp;</td>
-          </tr>
   </table>
       </div>
   </div>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 6307c69..315c977 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -4,25 +4,25 @@
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 
 
-sdk.linux32_bundle_download=adt-bundle-linux-x86.zip
-sdk.linux32_bundle_bytes=418614971
-sdk.linux32_bundle_checksum=24506708af221a887326c2a9ca9625dc
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130219.zip
+sdk.linux32_bundle_bytes=418664018
+sdk.linux32_bundle_checksum=e56ebb5c8eb84eb3227cf7c255373f4b
 
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64.zip
-sdk.linux64_bundle_bytes=418889835
-sdk.linux64_bundle_checksum=464c1fbe92ea293d6b2292c27af5066a
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130219.zip
+sdk.linux64_bundle_bytes=418939098
+sdk.linux64_bundle_checksum=90cb420934170787938d0477c1a83a7f
 
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
-sdk.mac64_bundle_bytes=390649300
-sdk.mac64_bundle_checksum=f557bc61a4bff466633037839771bffb
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130219.zip
+sdk.mac64_bundle_bytes=390697025
+sdk.mac64_bundle_checksum=b768c28f380c1846479664c4790e9c53
 
-sdk.win32_bundle_download=adt-bundle-windows-x86.zip
-sdk.win32_bundle_bytes=425429957
-sdk.win32_bundle_checksum=cca97f12904774385a57d542e70a490f
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130219.zip
+sdk.win32_bundle_bytes=425487608
+sdk.win32_bundle_checksum=4a40039f28048e6d7b2440adf55b8321
 
-sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
-sdk.win64_bundle_bytes=425553759
-sdk.win64_bundle_checksum=c51679f4517e1c3ddefa1e662bbf17f6
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130219.zip
+sdk.win64_bundle_bytes=425611626
+sdk.win64_bundle_checksum=891f79816b4d19042faab26d670f4f77
 
 
 
diff --git a/docs/html/tools/extras/support-library.jd b/docs/html/tools/extras/support-library.jd
index 08ac172..6475e3c 100644
--- a/docs/html/tools/extras/support-library.jd
+++ b/docs/html/tools/extras/support-library.jd
@@ -46,10 +46,33 @@
 <p>The sections below provide notes about successive releases of
 the Support Package, as denoted by revision number.</p>
 
-
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
+/>Support Package, revision 12</a> <em>(February 2013)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Changes for v4 support library:</dt>
+      <dd>
+        <ul>
+          <li>Improved interaction behavior for {@link android.support.v4.view.ViewPager}.</li>
+          <li>Fixed a bug that could cause {@link android.support.v4.view.ViewPager} to select the
+            wrong page.</li>
+          <li>Fixed use of {@link android.support.v4.view.ViewPager#removeView removeView()} method
+            during layout for {@link android.support.v4.view.ViewPager}.</li>
+          <li>Fixed issue with {@link android.support.v4.widget.SearchViewCompat} where using the
+            back button to dismiss does not clear the search text. This fix only applies to
+            host API levels 14 and higher.</li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
 />Support Package, revision 11</a> <em>(November 2012)</em>
   </p>
   <div class="toggle-content-toggleme">
@@ -119,7 +142,7 @@
       <dt>Changes for v4 support library:</dt>
       <dd>
         <ul>
-          <li>Added support for notification features introduced in Android 4.1 (API Level 16) with
+          <li>Added support for notification features introduced in Android 4.1 (API level 16) with
           additions to {@link android.support.v4.app.NotificationCompat}.</li>
         </ul>
       </dd>
@@ -210,7 +233,7 @@
           <li>Fixed intent flags for {@link android.app.PendingIntent} objects generated
             by {@link android.support.v4.app.TaskStackBuilder}.</li>
           <li>Removed unused attributes from the gridlayout library projects to make sure
-            the library can be built with API Level 7 and higher.</li>
+            the library can be built with API level 7 and higher.</li>
           <li>Added {@code .classpath} and {@code .project} files for the gridlayout
             library project.</li>
         </ul>
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index c1bc185..31cec0e 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -44,11 +44,28 @@
 SDK tools to revision 20 or later and restart the Android SDK Manager. If you do not,
 the Android 4.2 system components will not be available for download.</p>
 
-
 <div class="toggle-content opened">
 
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 2</a> <em>(February 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Maintenance update. The system version is 4.2.2.</p>
+    <dl>
+      <dt>Dependencies:</dt>
+      <dd>SDK Tools r21 or higher is required.</dd>
+    </dl>
+
+  </div>
+</div>
+
+<div class="toggle-content closed">
+
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
 class="toggle-content-img" alt="" />Revision 1</a> <em>(November 2012)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 4adb7b2..a3f53bbe 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -69,7 +69,7 @@
       <li>Java 1.6 or higher is required for ADT 21.1.0.</li>
       <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.1.0.</li>
       <li>ADT 21.1.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
-      Tools r21.1.0</a>. If you haven't already installed SDK Tools r21.1.0 into your SDK, use the
+      Tools r21.1</a>. If you haven't already installed SDK Tools r21.1 into your SDK, use the
       Android SDK Manager to do so.</li>
     </ul>
   </dd>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index a5b7eee..7d121844 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,7 +28,7 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
-      alt=""/>SDK Tools, Revision 21.1.0</a> <em>(February 2013)</em>
+      alt=""/>SDK Tools, Revision 21.1</a> <em>(February 2013)</em>
   </p>
 
   <div class="toggle-content-toggleme">
@@ -38,7 +38,7 @@
     <dd>
       <ul>
         <li>Android SDK Platform-tools revision 16 or later.</li>
-        <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1.0 is
+        <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1 is
           designed for use with ADT 21.1.0 and later. If you haven't already, update your
         <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.1.0.</li>
         <li>If you are developing outside Eclipse, you must have
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index e94ddae..fc84715 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -37,8 +37,8 @@
  * Canvas and Drawables</a> developer guide.</p></div>
  */
 public class Canvas {
-    // assigned in constructors, freed in finalizer
-    final int mNativeCanvas;
+    // assigned in constructors or setBitmap, freed in finalizer
+    int mNativeCanvas;
     
     // may be null
     private Bitmap mBitmap;
@@ -71,7 +71,7 @@
     private final CanvasFinalizer mFinalizer;
 
     private static class CanvasFinalizer {
-        private final int mNativeCanvas;
+        private int mNativeCanvas;
 
         public CanvasFinalizer(int nativeCanvas) {
             mNativeCanvas = nativeCanvas;
@@ -131,6 +131,18 @@
     }
 
     /**
+     * Replace existing canvas while ensuring that the swap has occurred before
+     * the previous native canvas is unreferenced.
+     */
+    private void safeCanvasSwap(int nativeCanvas) {
+        final int oldCanvas = mNativeCanvas;
+        mNativeCanvas = nativeCanvas;
+        mFinalizer.mNativeCanvas = nativeCanvas;
+        copyNativeCanvasState(oldCanvas, mNativeCanvas);
+        finalizer(oldCanvas);
+    }
+    
+    /**
      * Returns null.
      * 
      * @deprecated This method is not supported and should not be invoked.
@@ -156,11 +168,11 @@
     }
 
     /**
-     * Specify a bitmap for the canvas to draw into.  As a side-effect, also
-     * updates the canvas's target density to match that of the bitmap.
+     * Specify a bitmap for the canvas to draw into. As a side-effect, the
+     * canvas' target density is updated to match that of the bitmap while all
+     * other state such as the layers, filters, matrix, and clip are reset.
      *
      * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
-     * 
      * @see #setDensity(int)
      * @see #getDensity()
      */
@@ -169,17 +181,19 @@
             throw new RuntimeException("Can't set a bitmap device on a GL canvas");
         }
 
-        int pointer = 0;
-        if (bitmap != null) {
+        if (bitmap == null) {
+            safeCanvasSwap(initRaster(0));
+            mDensity = Bitmap.DENSITY_NONE;
+        } else {
             if (!bitmap.isMutable()) {
                 throw new IllegalStateException();
             }
             throwIfRecycled(bitmap);
+
+            safeCanvasSwap(initRaster(bitmap.ni()));
             mDensity = bitmap.mDensity;
-            pointer = bitmap.ni();
         }
 
-        native_setBitmap(mNativeCanvas, pointer);
         mBitmap = bitmap;
     }
     
@@ -694,7 +708,7 @@
      *              does not intersect with the canvas' clip
      */
     public boolean quickReject(RectF rect, EdgeType type) {
-        return native_quickReject(mNativeCanvas, rect, type.nativeInt);
+        return native_quickReject(mNativeCanvas, rect);
     }
 
     /**
@@ -714,7 +728,7 @@
      *                    does not intersect with the canvas' clip
      */
     public boolean quickReject(Path path, EdgeType type) {
-        return native_quickReject(mNativeCanvas, path.ni(), type.nativeInt);
+        return native_quickReject(mNativeCanvas, path.ni());
     }
 
     /**
@@ -737,9 +751,9 @@
      * @return            true if the rect (transformed by the canvas' matrix)
      *                    does not intersect with the canvas' clip
      */
-    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
-        return native_quickReject(mNativeCanvas, left, top, right, bottom,
-                                  type.nativeInt);
+    public boolean quickReject(float left, float top, float right, float bottom,
+                               EdgeType type) {
+        return native_quickReject(mNativeCanvas, left, top, right, bottom);
     }
 
     /**
@@ -1599,7 +1613,7 @@
     public static native void freeTextLayoutCaches();
 
     private static native int initRaster(int nativeBitmapOrZero);
-    private static native void native_setBitmap(int nativeCanvas, int bitmap);
+    private static native void copyNativeCanvasState(int srcCanvas, int dstCanvas);
     private static native int native_saveLayer(int nativeCanvas, RectF bounds,
                                                int paint, int layerFlags);
     private static native int native_saveLayer(int nativeCanvas, float l,
@@ -1630,15 +1644,12 @@
                                                        Rect bounds);
     private static native void native_getCTM(int canvas, int matrix);
     private static native boolean native_quickReject(int nativeCanvas,
-                                                     RectF rect,
-                                                     int native_edgeType);
+                                                     RectF rect);
     private static native boolean native_quickReject(int nativeCanvas,
-                                                     int path,
-                                                     int native_edgeType);
+                                                     int path);
     private static native boolean native_quickReject(int nativeCanvas,
                                                      float left, float top,
-                                                     float right, float bottom,
-                                                     int native_edgeType);
+                                                     float right, float bottom);
     private static native void native_drawRGB(int nativeCanvas, int r, int g,
                                               int b);
     private static native void native_drawARGB(int nativeCanvas, int a, int r,
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index f6b5ffc..157c7d1 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -375,9 +375,9 @@
      */
     public enum Direction {
         /** clockwise */
-        CW  (0),    // must match enum in SkPath.h
+        CW  (1),    // must match enum in SkPath.h
         /** counter-clockwise */
-        CCW (1);    // must match enum in SkPath.h
+        CCW (2);    // must match enum in SkPath.h
         
         Direction(int ni) {
             nativeInt = ni;
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 4487a3c..c68c9f7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -225,16 +225,4 @@
     private static native int  nativeGetStyle(int native_instance);
     private static native int  nativeCreateFromAsset(AssetManager mgr, String path);
     private static native int nativeCreateFromFile(String path);
-
-    /**
-     * Set the global gamma coefficients for black and white text. This call is
-     * usually a no-op in shipping products, and only exists for testing during
-     * development.
-     *
-     * @param blackGamma gamma coefficient for black text
-     * @param whiteGamma gamma coefficient for white text
-     *
-     * @hide - this is just for calibrating devices, not for normal apps
-     */
-    public static native void setGammaForText(float blackGamma, float whiteGamma);
 }
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 1c83c51..a99cdad 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -1246,24 +1246,6 @@
     }
 
     /**
-     *
-     *
-     * @hide
-     *
-     */
-    public SurfaceTexture getSurfaceTexture() {
-        if ((mUsage & USAGE_IO_INPUT) == 0) {
-            throw new RSInvalidStateException("Allocation is not a surface texture.");
-        }
-
-        int id = mRS.nAllocationGetSurfaceTextureID(getID(mRS));
-        SurfaceTexture st = new SurfaceTexture(id);
-        mRS.nAllocationGetSurfaceTextureID2(getID(mRS), st);
-
-        return st;
-    }
-
-    /**
      * For allocations used with io operations, returns the handle
      * onto a raw buffer that is being managed by the screen
      * compositor.
@@ -1272,7 +1254,17 @@
      *
      */
     public Surface getSurface() {
-        return new Surface(getSurfaceTexture());
+        if ((mUsage & USAGE_IO_INPUT) == 0) {
+            throw new RSInvalidStateException("Allocation is not a surface texture.");
+        }
+        return mRS.nAllocationGetSurface(getID(mRS));
+    }
+
+    /**
+     * @hide
+     */
+    public void setSurfaceTexture(SurfaceTexture st) {
+        setSurface(new Surface(st));
     }
 
     /**
@@ -1290,19 +1282,6 @@
     }
 
     /**
-     * @hide
-     */
-    public void setSurfaceTexture(SurfaceTexture st) {
-        mRS.validate();
-        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
-            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
-        }
-
-        Surface s = new Surface(st);
-        mRS.nAllocationSetSurface(getID(mRS), s);
-    }
-
-    /**
      * Creates a RenderScript allocation from a bitmap.
      *
      * With target API version 18 or greater, this allocation will be
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 10f4daa..bef28aa 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -102,6 +102,16 @@
         f.mkdirs();
     }
 
+    public enum ContextType {
+        NORMAL (0),
+        DEBUG (1),
+        PROFILE (2);
+
+        int mID;
+        ContextType(int id) {
+            mID = id;
+        }
+    }
 
     // Methods below are wrapped to protect the non-threadsafe
     // lockless fifo.
@@ -122,9 +132,9 @@
                                   stencilMin, stencilPref,
                                   samplesMin, samplesPref, samplesQ, dpi);
     }
-    native int  rsnContextCreate(int dev, int ver, int sdkVer);
-    synchronized int nContextCreate(int dev, int ver, int sdkVer) {
-        return rsnContextCreate(dev, ver, sdkVer);
+    native int  rsnContextCreate(int dev, int ver, int sdkVer, int contextType);
+    synchronized int nContextCreate(int dev, int ver, int sdkVer, int contextType) {
+        return rsnContextCreate(dev, ver, sdkVer, contextType);
     }
     native void rsnContextDestroy(int con);
     synchronized void nContextDestroy() {
@@ -303,15 +313,10 @@
         validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
-    native int rsnAllocationGetSurfaceTextureID(int con, int alloc);
-    synchronized int nAllocationGetSurfaceTextureID(int alloc) {
+    native Surface rsnAllocationGetSurface(int con, int alloc);
+    synchronized Surface nAllocationGetSurface(int alloc) {
         validate();
-        return rsnAllocationGetSurfaceTextureID(mContext, alloc);
-    }
-    native void rsnAllocationGetSurfaceTextureID2(int con, int alloc, SurfaceTexture st);
-    synchronized void nAllocationGetSurfaceTextureID2(int alloc, SurfaceTexture st) {
-        validate();
-        rsnAllocationGetSurfaceTextureID2(mContext, alloc, st);
+        return rsnAllocationGetSurface(mContext, alloc);
     }
     native void rsnAllocationSetSurface(int con, int alloc, Surface sur);
     synchronized void nAllocationSetSurface(int alloc, Surface sur) {
@@ -1017,17 +1022,24 @@
     }
 
     /**
+     * @hide
+     */
+    public static RenderScript create(Context ctx, int sdkVersion) {
+        return create(ctx, sdkVersion, ContextType.NORMAL);
+    }
+
+    /**
      * Create a basic RenderScript context.
      *
      * @hide
      * @param ctx The context.
      * @return RenderScript
      */
-    public static RenderScript create(Context ctx, int sdkVersion) {
+    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
         RenderScript rs = new RenderScript(ctx);
 
         rs.mDev = rs.nDeviceCreate();
-        rs.mContext = rs.nContextCreate(rs.mDev, 0, sdkVersion);
+        rs.mContext = rs.nContextCreate(rs.mDev, 0, sdkVersion, ct.mID);
         if (rs.mContext == 0) {
             throw new RSDriverException("Failed to create RS context.");
         }
@@ -1043,8 +1055,20 @@
      * @return RenderScript
      */
     public static RenderScript create(Context ctx) {
+        return create(ctx, ContextType.NORMAL);
+    }
+
+    /**
+     * Create a basic RenderScript context.
+     *
+     * @hide
+     *
+     * @param ctx The context.
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, ContextType ct) {
         int v = ctx.getApplicationInfo().targetSdkVersion;
-        return create(ctx, v);
+        return create(ctx, v, ct);
     }
 
     /**
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 5e631af..8757b19 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -182,10 +182,10 @@
 }
 
 static jint
-nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver, jint sdkVer)
+nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver, jint sdkVer, jint ct)
 {
     LOG_API("nContextCreate");
-    return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer);
+    return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, false, false);
 }
 
 static jint
@@ -237,23 +237,6 @@
 }
 
 static void
-nContextSetSurfaceTexture(JNIEnv *_env, jobject _this, RsContext con, jint width, jint height, jobject sur)
-{
-    LOG_API("nContextSetSurfaceTexture, con(%p), width(%i), height(%i), surface(%p)", con, width, height, (Surface *)sur);
-
-    sp<ANativeWindow> window;
-    sp<GLConsumer> st;
-    if (sur == 0) {
-
-    } else {
-        st = SurfaceTexture_getSurfaceTexture(_env, sur);
-        window = new Surface(st->getBufferQueue());
-    }
-
-    rsContextSetSurface(con, width, height, window.get());
-}
-
-static void
 nContextDestroy(JNIEnv *_env, jobject _this, RsContext con)
 {
     LOG_API("nContextDestroy, con(%p)", con);
@@ -487,20 +470,17 @@
     rsAllocationSyncAll(con, (RsAllocation)a, (RsAllocationUsageType)bits);
 }
 
-static jint
-nAllocationGetSurfaceTextureID(JNIEnv *_env, jobject _this, RsContext con, jint a)
+static jobject
+nAllocationGetSurface(JNIEnv *_env, jobject _this, RsContext con, jint a)
 {
-    LOG_API("nAllocationGetSurfaceTextureID, con(%p), a(%p)", con, (RsAllocation)a);
-    return rsAllocationGetSurfaceTextureID(con, (RsAllocation)a);
-}
+    LOG_API("nAllocationGetSurface, con(%p), a(%p)", con, (RsAllocation)a);
 
-static void
-nAllocationGetSurfaceTextureID2(JNIEnv *_env, jobject _this, RsContext con, jint a, jobject jst)
-{
-    LOG_API("nAllocationGetSurfaceTextureID2, con(%p), a(%p)", con, (RsAllocation)a);
-    sp<GLConsumer> st = SurfaceTexture_getSurfaceTexture(_env, jst);
+    IGraphicBufferProducer *v = (IGraphicBufferProducer *)rsAllocationGetSurface(con, (RsAllocation)a);
+    sp<IGraphicBufferProducer> bp = v;
+    v->decStrong(NULL);
 
-    rsAllocationGetSurfaceTextureID2(con, (RsAllocation)a, st.get(), sizeof(GLConsumer *));
+    jobject o = android_view_Surface_createFromIGraphicBufferProducer(_env, bp);
+    return o;
 }
 
 static void
@@ -1483,12 +1463,11 @@
 
 
 // All methods below are thread protected in java.
-{"rsnContextCreate",                 "(III)I",                                (void*)nContextCreate },
+{"rsnContextCreate",                 "(IIII)I",                               (void*)nContextCreate },
 {"rsnContextCreateGL",               "(IIIIIIIIIIIIIFI)I",                    (void*)nContextCreateGL },
 {"rsnContextFinish",                 "(I)V",                                  (void*)nContextFinish },
 {"rsnContextSetPriority",            "(II)V",                                 (void*)nContextSetPriority },
 {"rsnContextSetSurface",             "(IIILandroid/view/Surface;)V",          (void*)nContextSetSurface },
-{"rsnContextSetSurfaceTexture",      "(IIILandroid/graphics/SurfaceTexture;)V", (void*)nContextSetSurfaceTexture },
 {"rsnContextDestroy",                "(I)V",                                  (void*)nContextDestroy },
 {"rsnContextDump",                   "(II)V",                                 (void*)nContextDump },
 {"rsnContextPause",                  "(I)V",                                  (void*)nContextPause },
@@ -1526,8 +1505,7 @@
 {"rsnAllocationCopyToBitmap",        "(IILandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
 
 {"rsnAllocationSyncAll",             "(III)V",                                (void*)nAllocationSyncAll },
-{"rsnAllocationGetSurfaceTextureID", "(II)I",                                 (void*)nAllocationGetSurfaceTextureID },
-{"rsnAllocationGetSurfaceTextureID2","(IILandroid/graphics/SurfaceTexture;)V",(void*)nAllocationGetSurfaceTextureID2 },
+{"rsnAllocationGetSurface",          "(II)Landroid/view/Surface;",            (void*)nAllocationGetSurface },
 {"rsnAllocationSetSurface",          "(IILandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
 {"rsnAllocationIoSend",              "(II)V",                                 (void*)nAllocationIoSend },
 {"rsnAllocationIoReceive",           "(II)V",                                 (void*)nAllocationIoReceive },
diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp
index d3fb98d..1dfec23 100644
--- a/libs/androidfw/StreamingZipInflater.cpp
+++ b/libs/androidfw/StreamingZipInflater.cpp
@@ -23,6 +23,23 @@
 #include <string.h>
 #include <stddef.h>
 #include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
 
 static inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
 
@@ -135,7 +152,7 @@
             // if we don't have any data to decode, read some in.  If we're working
             // from mmapped data this won't happen, because the clipping to total size
             // will prevent reading off the end of the mapped input chunk.
-            if (mInflateState.avail_in == 0) {
+            if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) {
                 int err = readNextChunk();
                 if (err < 0) {
                     ALOGE("Unable to access asset data: %d", err);
@@ -191,11 +208,10 @@
     if (mInNextChunkOffset < mInTotalSize) {
         size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
         if (toRead > 0) {
-            ssize_t didRead = ::read(mFd, mInBuf, toRead);
+            ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead));
             //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
             if (didRead < 0) {
-                // TODO: error
-                ALOGE("Error reading asset data");
+                ALOGE("Error reading asset data: %s", strerror(errno));
                 return didRead;
             } else {
                 mInNextChunkOffset += didRead;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5f2a4d5..33d8063 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -48,6 +48,7 @@
 		external/skia/include/core \
 		external/skia/include/effects \
 		external/skia/include/images \
+		external/skia/src/core \
 		external/skia/src/ports \
 		external/skia/include/utils \
 		$(intermediates) \
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 398f719..bdd539e 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -251,16 +251,18 @@
  * display list. This function should remain in sync with the replay() function.
  */
 void DisplayList::output(uint32_t level) {
-    ALOGD("%*sStart display list (%p, %s, render=%d)", level * 2, "", this,
+    ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
             mName.string(), isRenderable());
+    ALOGD("%*s%s %d", level * 2, "", "Save",
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
-    ALOGD("%*s%s %d", level * 2, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     outputViewProperties(level);
     int flags = DisplayListOp::kOpLogFlag_Recurse;
     for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
         mDisplayListData->displayListOps[i]->output(level, flags);
     }
-    ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
+
+    ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
 }
 
 float DisplayList::getPivotX() {
@@ -356,7 +358,9 @@
     }
 }
 
-void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
+status_t DisplayList::setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
+        int32_t flags, uint32_t level, DeferredDisplayList* deferredList) {
+    status_t status = DrawGlInfo::kStatusDone;
 #if DEBUG_DISPLAYLIST
     outputViewProperties(level);
 #endif
@@ -377,6 +381,11 @@
         }
     }
     if (mAlpha < 1 && !mCaching) {
+        if (deferredList) {
+            // flush since we'll either enter a Layer, or set alpha, both not supported in deferral
+            status |= deferredList->flush(renderer, dirty, flags, level);
+        }
+
         if (!mHasOverlappingRendering) {
             renderer.setAlpha(mAlpha);
         } else {
@@ -392,9 +401,14 @@
         }
     }
     if (mClipChildren && !mCaching) {
+        if (deferredList && CC_UNLIKELY(!renderer.hasRectToRectTransform())) {
+            // flush, since clip will likely be a region
+            status |= deferredList->flush(renderer, dirty, flags, level);
+        }
         renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
                 SkRegion::kIntersect_Op);
     }
+    return status;
 }
 
 status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
@@ -414,12 +428,7 @@
     DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
 
-    if (mAlpha < 1 && !mCaching && CC_LIKELY(deferredList)) {
-        // flush before a saveLayerAlpha/setAlpha
-        // TODO: make this cleaner
-        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
-    }
-    setViewProperties(renderer, level);
+    drawGlStatus |= setViewProperties(renderer, dirty, flags, level, deferredList);
 
     if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
         DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 86c9ec0..feee69c 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -17,6 +17,10 @@
 #ifndef ANDROID_HWUI_DISPLAY_LIST_H
 #define ANDROID_HWUI_DISPLAY_LIST_H
 
+#ifndef LOG_TAG
+    #define LOG_TAG "OpenGLRenderer"
+#endif
+
 #include <SkCamera.h>
 #include <SkMatrix.h>
 
@@ -75,7 +79,8 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
+    status_t setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
+            int32_t flags, uint32_t level, DeferredDisplayList* deferredList);
     void outputViewProperties(uint32_t level);
 
     ANDROID_API size_t getSize();
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 1bae0ff..97812d4 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -17,6 +17,10 @@
 #ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
 #define ANDROID_HWUI_DISPLAY_OPERATION_H
 
+#ifndef LOG_TAG
+    #define LOG_TAG "OpenGLRenderer"
+#endif
+
 #include <SkXfermode.h>
 
 #include <private/hwui/DrawGlInfo.h>
@@ -100,7 +104,7 @@
     virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
             uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
         status_t status = DrawGlInfo::kStatusDone;
-        if (deferredList && requiresDrawOpFlush()) {
+        if (deferredList && requiresDrawOpFlush(renderer)) {
             // will be setting renderer state that affects ops in deferredList, so flush list first
             status |= deferredList->flush(renderer, dirty, flags, level);
         }
@@ -114,7 +118,7 @@
      * Returns true if it affects renderer drawing state in such a way to break deferral
      * see OpenGLRenderer::disallowDeferral()
      */
-    virtual bool requiresDrawOpFlush() { return false; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return false; }
 };
 
 class DrawOp : public DisplayListOp {
@@ -272,7 +276,7 @@
     }
 
     virtual const char* name() { return "SaveLayer"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     Rect mArea;
@@ -294,7 +298,7 @@
     }
 
     virtual const char* name() { return "SaveLayerAlpha"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     Rect mArea;
@@ -434,7 +438,16 @@
 
     virtual const char* name() { return "ClipRect"; }
 
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) {
+        // TODO: currently, we flush when we *might* cause a clip region to exist. Ideally, we
+        // should only flush when a non-rectangular clip would result
+        return !renderer.hasRectToRectTransform() || !hasRectToRectOp();
+    }
+
 private:
+    inline bool hasRectToRectOp() {
+        return mOp == SkRegion::kIntersect_Op || mOp == SkRegion::kReplace_Op;
+    }
     Rect mArea;
     SkRegion::Op mOp;
 };
@@ -455,7 +468,7 @@
     }
 
     virtual const char* name() { return "ClipPath"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     SkPath* mPath;
@@ -478,7 +491,7 @@
     }
 
     virtual const char* name() { return "ClipRegion"; }
-    virtual bool requiresDrawOpFlush() { return true; }
+    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     SkRegion* mRegion;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1d9eb0e..db65b88 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
+#include <SkGlyph.h>
 #include <SkUtils.h>
 
 #include <cutils/properties.h>
@@ -562,9 +563,15 @@
     int penX = radius - bounds.left;
     int penY = radius - bounds.bottom;
 
-    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
-            Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
-    blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
+    if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
+        // text has non-whitespace, so draw and blur to create the shadow
+        // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
+        // TODO: don't draw pure whitespace in the first place, and avoid needing this check
+        mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
+                Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
+
+        blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
+    }
 
     DropShadow image;
     image.width = paddedWidth;
@@ -773,6 +780,7 @@
 
         delete[] gaussian;
         delete[] scratch;
+        return;
     }
 
     uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 664b2f8..ccf1da5 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -23,6 +23,7 @@
 
 #include <ui/Region.h>
 
+#include <SkPaint.h>
 #include <SkXfermode.h>
 
 #include "Rect.h"
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6b614a7..1afeaf0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -81,7 +81,7 @@
     { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kMultiply_Mode, GL_ZERO,                GL_SRC_COLOR },
+    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
     { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
 };
 
@@ -102,7 +102,7 @@
     { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kMultiply_Mode, GL_DST_COLOR,           GL_ZERO },
+    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
 };
 
@@ -1284,6 +1284,10 @@
     }
 }
 
+bool OpenGLRenderer::hasRectToRectTransform() {
+    return CC_LIKELY(mSnapshot->transform->rectToRect());
+}
+
 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
     mSnapshot->transform->copyTo(*matrix);
 }
@@ -1505,8 +1509,10 @@
     if (clear) clearLayerRegions();
     // Make sure setScissor & setStencil happen at the beginning of
     // this method
-    if (mDirtyClip && mCaches.scissorEnabled) {
-        setScissorFromClip();
+    if (mDirtyClip) {
+        if (mCaches.scissorEnabled) {
+            setScissorFromClip();
+        }
         setStencilFromClip();
     }
     mDescription.reset();
@@ -1801,7 +1807,7 @@
 
 void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
     if (displayList) {
-        displayList->output(0);
+        displayList->output(1);
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e12083c..80f2081 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -198,6 +198,7 @@
     virtual void scale(float sx, float sy);
     virtual void skew(float sx, float sy);
 
+    bool hasRectToRectTransform();
     ANDROID_API void getMatrix(SkMatrix* matrix);
     virtual void setMatrix(SkMatrix* matrix);
     virtual void concatMatrix(SkMatrix* matrix);
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 19a5db7..923913e 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -132,15 +132,6 @@
             }
             break;
         }
-        case SkRegion::kUnion_Op: {
-            if (CC_UNLIKELY(!clipRegion->isEmpty())) {
-                ensureClipRegion();
-                clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kUnion_Op);
-            } else {
-                clipped = clipRect->unionWith(r);
-            }
-            break;
-        }
         case SkRegion::kReplace_Op: {
             setClip(r.left, r.top, r.right, r.bottom);
             clipped = true;
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index f653592..24b0523 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <SkGlyph.h>
 #include <utils/Log.h>
 
 #include "Debug.h"
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 8c5a8ff..1a75ea8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -20,6 +20,7 @@
 
 #include <utils/JenkinsHash.h>
 
+#include <SkGlyph.h>
 #include <SkUtils.h>
 
 #include "Debug.h"
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.h b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
index afedcbd..374604c 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.h
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.h
@@ -33,6 +33,7 @@
      //! Return the allocation size for the pixels
     size_t getSize() const { return mSize; }
 
+    SK_DECLARE_UNFLATTENABLE_OBJECT()
 protected:
     // overrides from SkPixelRef
     virtual void* onLockPixels(SkColorTable**);
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index 2eeae62..e99d412 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -914,7 +914,7 @@
         java.nio.IntBuffer shaders
     );
 
-    // C function int glGetAttribLocation ( GLuint program, const char *name )
+    // C function GLint glGetAttribLocation ( GLuint program, const char *name )
 
     public static native int glGetAttribLocation(
         int program,
@@ -1236,7 +1236,7 @@
         java.nio.IntBuffer params
     );
 
-    // C function int glGetUniformLocation ( GLuint program, const char *name )
+    // C function GLint glGetUniformLocation ( GLuint program, const char *name )
 
     public static native int glGetUniformLocation(
         int program,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 024faf7..f0b1d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -429,7 +429,7 @@
         mHasFlipSettings = res.getBoolean(R.bool.config_hasFlipSettingsPanel);
 
         mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
-        if (mHasFlipSettings) {
+        if (mDateTimeView != null) {
             mDateTimeView.setOnClickListener(mClockClickListener);
             mDateTimeView.setEnabled(true);
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index acbde9b..0e545c6 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -361,6 +361,7 @@
 
     static final Rect mTmpParentFrame = new Rect();
     static final Rect mTmpDisplayFrame = new Rect();
+    static final Rect mTmpOverscanFrame = new Rect();
     static final Rect mTmpContentFrame = new Rect();
     static final Rect mTmpVisibleFrame = new Rect();
     static final Rect mTmpNavigationFrame = new Rect();
@@ -1737,6 +1738,51 @@
         return 0;
     }
 
+    @Override
+    public void selectRotationAnimationLw(int anim[]) {
+        if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
+                + mTopFullscreenOpaqueWindowState + " rotationAnimation="
+                + (mTopFullscreenOpaqueWindowState == null ?
+                        "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation));
+        if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen) {
+            switch (mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) {
+                case ROTATION_ANIMATION_CROSSFADE:
+                    anim[0] = R.anim.rotation_animation_xfade_exit;
+                    anim[1] = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_JUMPCUT:
+                    anim[0] = R.anim.rotation_animation_jump_exit;
+                    anim[1] = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_ROTATE:
+                default:
+                    anim[0] = anim[1] = 0;
+                    break;
+            }
+        } else {
+            anim[0] = anim[1] = 0;
+        }
+    }
+
+    @Override
+    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
+            boolean forceDefault) {
+        switch (exitAnimId) {
+            case R.anim.rotation_animation_xfade_exit:
+            case R.anim.rotation_animation_jump_exit:
+                // These are the only cases that matter.
+                if (forceDefault) {
+                    return false;
+                }
+                int anim[] = new int[2];
+                selectRotationAnimationLw(anim);
+                return (exitAnimId == anim[0] && enterAnimId == anim[1]);
+            default:
+                return true;
+        }
+    }
+
+    @Override
     public Animation createForceHideEnterAnimation(boolean onWallpaper) {
         return AnimationUtils.loadAnimation(mContext, onWallpaper
                 ? com.android.internal.R.anim.lock_screen_wallpaper_behind_enter
@@ -2448,11 +2494,12 @@
         // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
+        final Rect of = mTmpOverscanFrame;
         final Rect vf = mTmpVisibleFrame;
-        pf.left = df.left = vf.left = mDockLeft;
-        pf.top = df.top = vf.top = mDockTop;
-        pf.right = df.right = vf.right = mDockRight;
-        pf.bottom = df.bottom = vf.bottom = mDockBottom;
+        pf.left = df.left = of.left = vf.left = mDockLeft;
+        pf.top = df.top = of.top = vf.top = mDockTop;
+        pf.right = df.right = of.right = vf.right = mDockRight;
+        pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom;
 
         if (isDefaultDisplay) {
             // For purposes of putting out fake window up to steal focus, we will
@@ -2538,7 +2585,7 @@
                 mStatusBarLayer = mNavigationBar.getSurfaceLayer();
                 // And compute the final frame.
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
-                        mTmpNavigationFrame, mTmpNavigationFrame);
+                        mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame);
                 if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
             }
             if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
@@ -2547,10 +2594,11 @@
             // decide where the status bar goes ahead of time
             if (mStatusBar != null) {
                 // apply any navigation bar insets
-                pf.left = df.left = mUnrestrictedScreenLeft;
-                pf.top = df.top = mUnrestrictedScreenTop;
-                pf.right = df.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
-                pf.bottom = df.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
+                pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+                pf.top = df.top = of.top = mUnrestrictedScreenTop;
+                pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+                pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight
+                        + mUnrestrictedScreenTop;
                 vf.left = mStableLeft;
                 vf.top = mStableTop;
                 vf.right = mStableRight;
@@ -2559,7 +2607,7 @@
                 mStatusBarLayer = mStatusBar.getSurfaceLayer();
 
                 // Let the status bar determine its size.
-                mStatusBar.computeFrameLw(pf, df, vf, vf);
+                mStatusBar.computeFrameLw(pf, df, vf, vf, vf);
 
                 // For layout, the status bar is always at the top with our fixed height.
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
@@ -2605,8 +2653,8 @@
         return 0;
     }
 
-    void setAttachedWindowFrames(WindowState win, int fl, int adjust,
-            WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
+    void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
+            boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
         if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
             // Here's a special case: if this attached window is a panel that is
             // above the dock window, and the window it is attached to is below
@@ -2615,10 +2663,10 @@
             // of the underlying window and the attached window is floating on top
             // of the whole thing.  So, we ignore the attached window and explicitly
             // compute the frames that would be appropriate without the dock.
-            df.left = cf.left = vf.left = mDockLeft;
-            df.top = cf.top = vf.top = mDockTop;
-            df.right = cf.right = vf.right = mDockRight;
-            df.bottom = cf.bottom = vf.bottom = mDockBottom;
+            df.left = of.left = cf.left = vf.left = mDockLeft;
+            df.top = of.top = cf.top = vf.top = mDockTop;
+            df.right = of.right = cf.right = vf.right = mDockRight;
+            df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom;
         } else {
             // The effective display frame of the attached window depends on
             // whether it is taking care of insetting its content.  If not,
@@ -2627,7 +2675,7 @@
             // the display frame and let the attached window take care of
             // positioning its content appropriately.
             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                cf.set(attached.getDisplayFrameLw());
+                cf.set(attached.getOverscanFrameLw());
             } else {
                 // If the window is resizing, then we want to base the content
                 // frame on our attached content frame to resize...  however,
@@ -2644,6 +2692,7 @@
                 }
             }
             df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
+            of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
             vf.set(attached.getVisibleFrameLw());
         }
         // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
@@ -2695,6 +2744,7 @@
 
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
+        final Rect of = mTmpOverscanFrame;
         final Rect cf = mTmpContentFrame;
         final Rect vf = mTmpVisibleFrame;
 
@@ -2707,31 +2757,30 @@
             if (attached != null) {
                 // If this window is attached to another, our display
                 // frame is the same as the one we are attached to.
-                setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
+                setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
             } else {
                 // Give the window full screen.
-                pf.left = df.left = cf.left = mOverscanScreenLeft;
-                pf.top = df.top = cf.top = mOverscanScreenTop;
-                pf.right = df.right = cf.right
+                pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                pf.right = df.right = of.right = cf.right
                         = mOverscanScreenLeft + mOverscanScreenWidth;
-                pf.bottom = df.bottom = cf.bottom
+                pf.bottom = df.bottom = of.bottom = cf.bottom
                         = mOverscanScreenTop + mOverscanScreenHeight;
             }
         } else  if (attrs.type == TYPE_INPUT_METHOD) {
-            pf.left = df.left = cf.left = vf.left = mDockLeft;
-            pf.top = df.top = cf.top = vf.top = mDockTop;
-            pf.right = df.right = cf.right = vf.right = mDockRight;
-            pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
+            pf.left = df.left = of.left = cf.left = vf.left = mDockLeft;
+            pf.top = df.top = of.top = cf.top = vf.top = mDockTop;
+            pf.right = df.right = of.right = cf.right = vf.right = mDockRight;
+            pf.bottom = df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom;
             // IM dock windows always go to the bottom of the screen.
             attrs.gravity = Gravity.BOTTOM;
             mDockLayer = win.getSurfaceLayer();
         } else {
-            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
-                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)
-                    && (sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
+            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
+                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
                 if (DEBUG_LAYOUT)
                     Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
-                            + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
+                            + "): IN_SCREEN, INSET_DECOR");
                 // This is the case for a normal activity window: we want it
                 // to cover all of the screen space, and it can take care of
                 // moving its contents to account for screen decorations that
@@ -2739,7 +2788,7 @@
                 if (attached != null) {
                     // If this window is attached to another, our display
                     // frame is the same as the one we are attached to.
-                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
+                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
                 } else {
                     if (attrs.type == TYPE_STATUS_BAR_PANEL
                             || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
@@ -2750,14 +2799,15 @@
                         //
                         // 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
-                                            ? mRestrictedScreenLeft+mRestrictedScreenWidth
-                                            : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                        pf.bottom = df.bottom = hasNavBar
-                                              ? mRestrictedScreenTop+mRestrictedScreenHeight
-                                              : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                        pf.left = df.left = of.left = hasNavBar
+                                ? mDockLeft : mUnrestrictedScreenLeft;
+                        pf.top = df.top = of.top = mUnrestrictedScreenTop;
+                        pf.right = df.right = of.right = hasNavBar
+                                ? mRestrictedScreenLeft+mRestrictedScreenWidth
+                                : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        pf.bottom = df.bottom = of.bottom = hasNavBar
+                                ? mRestrictedScreenTop+mRestrictedScreenHeight
+                                : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
 
                         if (DEBUG_LAYOUT) {
                             Log.v(TAG, String.format(
@@ -2769,10 +2819,11 @@
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                         // Asking to layout into the overscan region, so give it that pure
                         // unrestricted area.
-                        pf.left = df.left = mOverscanScreenLeft;
-                        pf.top = df.top = mOverscanScreenTop;
-                        pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                        pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+                        pf.left = df.left = of.left = mOverscanScreenLeft;
+                        pf.top = df.top = of.top = mOverscanScreenTop;
+                        pf.right = df.right = of.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                        pf.bottom = df.bottom = of.bottom = mOverscanScreenTop
+                                + mOverscanScreenHeight;
                     } else if (mCanHideNavigationBar
                             && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                             && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
@@ -2785,6 +2836,13 @@
                         pf.top = df.top = mOverscanScreenTop;
                         pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
                         pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+                        // We need to tell the app about where the frame inside the overscan
+                        // is, so it can inset its content by that amount -- it didn't ask
+                        // to actually extend itself into the overscan region.
+                        of.left = mUnrestrictedScreenLeft;
+                        of.top = mUnrestrictedScreenTop;
+                        of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                     } else {
                         pf.left = df.left = mRestrictedOverscanScreenLeft;
                         pf.top = df.top = mRestrictedOverscanScreenTop;
@@ -2792,18 +2850,36 @@
                                 + mRestrictedOverscanScreenWidth;
                         pf.bottom = df.bottom = mRestrictedOverscanScreenTop
                                 + mRestrictedOverscanScreenHeight;
+                        // We need to tell the app about where the frame inside the overscan
+                        // is, so it can inset its content by that amount -- it didn't ask
+                        // to actually extend itself into the overscan region.
+                        of.left = mUnrestrictedScreenLeft;
+                        of.top = mUnrestrictedScreenTop;
+                        of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                     }
 
-                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                        cf.left = mDockLeft;
-                        cf.top = mDockTop;
-                        cf.right = mDockRight;
-                        cf.bottom = mDockBottom;
+                    if ((attrs.flags&FLAG_FULLSCREEN) == 0) {
+                        if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                            cf.left = mDockLeft;
+                            cf.top = mDockTop;
+                            cf.right = mDockRight;
+                            cf.bottom = mDockBottom;
+                        } else {
+                            cf.left = mContentLeft;
+                            cf.top = mContentTop;
+                            cf.right = mContentRight;
+                            cf.bottom = mContentBottom;
+                        }
                     } else {
-                        cf.left = mContentLeft;
-                        cf.top = mContentTop;
-                        cf.right = mContentRight;
-                        cf.bottom = mContentBottom;
+                        // Full screen windows are always given a layout that is as if the
+                        // status bar and other transient decors are gone.  This is to avoid
+                        // bad states when moving from a window that is not hding the
+                        // status bar to one that is.
+                        cf.left = mRestrictedScreenLeft;
+                        cf.top = mRestrictedScreenTop;
+                        cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
+                        cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight;
                     }
 
                     applyStableConstraints(sysUiFl, fl, cf);
@@ -2825,12 +2901,13 @@
                 // gets everything, period.
                 if (attrs.type == TYPE_STATUS_BAR_PANEL
                         || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
-                    pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
-                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = cf.right = hasNavBar
+                    pf.left = df.left = of.left = cf.left = hasNavBar
+                            ? mDockLeft : mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = hasNavBar
                                         ? mRestrictedScreenLeft+mRestrictedScreenWidth
                                         : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom = hasNavBar
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar
                                           ? mRestrictedScreenTop+mRestrictedScreenHeight
                                           : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                     if (DEBUG_LAYOUT) {
@@ -2841,10 +2918,12 @@
                 } else if (attrs.type == TYPE_NAVIGATION_BAR
                         || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
                     // 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;
+                    pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = of.right = mUnrestrictedScreenLeft
+                            + mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop
+                            + mUnrestrictedScreenHeight;
                     if (DEBUG_LAYOUT) {
                         Log.v(TAG, String.format(
                                     "Laying out navigation bar window: (%d,%d - %d,%d)",
@@ -2854,36 +2933,39 @@
                                 || attrs.type == TYPE_BOOT_PROGRESS)
                         && ((fl & FLAG_FULLSCREEN) != 0)) {
                     // Fullscreen secure system overlays get what they ask for.
-                    pf.left = df.left = mOverscanScreenLeft;
-                    pf.top = df.top = mOverscanScreenTop;
-                    pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
+                            + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
+                            + mOverscanScreenHeight;
                 } else if (attrs.type == TYPE_BOOT_PROGRESS
                         || attrs.type == TYPE_UNIVERSE_BACKGROUND) {
                     // Boot progress screen always covers entire display.
-                    pf.left = df.left = cf.left = mOverscanScreenLeft;
-                    pf.top = df.top = cf.top = mOverscanScreenTop;
-                    pf.right = df.right = cf.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
-                            = mOverscanScreenTop + mOverscanScreenHeight;
+                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
+                            + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
+                            + mOverscanScreenHeight;
                 } else if (attrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
                     // The wallpaper mostly goes into the overscan region.
-                    pf.left = df.left = cf.left = mRestrictedOverscanScreenLeft;
-                    pf.top = df.top = cf.top = mRestrictedOverscanScreenTop;
-                    pf.right = df.right = cf.right
+                    pf.left = df.left = of.left = cf.left = mRestrictedOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mRestrictedOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right
                             = mRestrictedOverscanScreenLeft + mRestrictedOverscanScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
+                    pf.bottom = df.bottom = of.bottom = cf.bottom
                             = mRestrictedOverscanScreenTop + mRestrictedOverscanScreenHeight;
                 } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0
                         && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                         && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                     // Asking to layout into the overscan region, so give it that pure
                     // unrestricted area.
-                    pf.left = df.left = cf.left = mOverscanScreenLeft;
-                    pf.top = df.top = cf.top = mOverscanScreenTop;
-                    pf.right = df.right = cf.right
+                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right
                             = mOverscanScreenLeft + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
+                    pf.bottom = df.bottom = of.bottom = cf.bottom
                             = mOverscanScreenTop + mOverscanScreenHeight;
                 } else if (mCanHideNavigationBar
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
@@ -2896,17 +2978,19 @@
                     // XXX This assumes that an app asking for this will also
                     // ask for layout in only content.  We can't currently figure out
                     // what the screen would be if only laying out to hide the nav bar.
-                    pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
-                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
-                            = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                    pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = mUnrestrictedScreenLeft
+                            + mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
+                            + mUnrestrictedScreenHeight;
                 } else {
-                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
-                    pf.top = df.top = cf.top = mRestrictedScreenTop;
-                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
-                            = mRestrictedScreenTop+mRestrictedScreenHeight;
+                    pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
+                            + mRestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
+                            + mRestrictedScreenHeight;
                 }
 
                 applyStableConstraints(sysUiFl, fl, cf);
@@ -2924,7 +3008,7 @@
                     Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
                 // A child window should be placed inside of the same visible
                 // frame that its parent had.
-                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
+                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf);
             } else {
                 if (DEBUG_LAYOUT)
                     Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
@@ -2935,26 +3019,27 @@
                     // the status bar.  They are protected by the STATUS_BAR_SERVICE
                     // permission, so they have the same privileges as the status
                     // bar itself.
-                    pf.left = df.left = cf.left = mRestrictedScreenLeft;
-                    pf.top = df.top = cf.top = mRestrictedScreenTop;
-                    pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
-                    pf.bottom = df.bottom = cf.bottom
-                            = mRestrictedScreenTop+mRestrictedScreenHeight;
+                    pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
+                            + mRestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
+                            + mRestrictedScreenHeight;
                 } else {
                     pf.left = mContentLeft;
                     pf.top = mContentTop;
                     pf.right = mContentRight;
                     pf.bottom = mContentBottom;
                     if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                        df.left = cf.left = mDockLeft;
-                        df.top = cf.top = mDockTop;
-                        df.right = cf.right = mDockRight;
-                        df.bottom = cf.bottom = mDockBottom;
+                        df.left = of.left = cf.left = mDockLeft;
+                        df.top = of.top = cf.top = mDockTop;
+                        df.right = of.right = cf.right = mDockRight;
+                        df.bottom = of.bottom = cf.bottom = mDockBottom;
                     } else {
-                        df.left = cf.left = mContentLeft;
-                        df.top = cf.top = mContentTop;
-                        df.right = cf.right = mContentRight;
-                        df.bottom = cf.bottom = mContentBottom;
+                        df.left = of.left = cf.left = mContentLeft;
+                        df.top = of.top = cf.top = mContentTop;
+                        df.right = of.right = cf.right = mContentRight;
+                        df.bottom = of.bottom = cf.bottom = mContentBottom;
                     }
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                         vf.left = mCurLeft;
@@ -2969,8 +3054,9 @@
         }
 
         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
-            df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
-            df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
+            df.left = df.top = of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
+            df.right = df.bottom = of.right = of.bottom = cf.right = cf.bottom
+                    = vf.right = vf.bottom = 10000;
         }
 
         if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
@@ -2978,9 +3064,10 @@
                 + " attach=" + attached + " type=" + attrs.type 
                 + String.format(" flags=0x%08x", fl)
                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
+                + " of=" + of.toShortString()
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
 
-        win.computeFrameLw(pf, df, cf, vf);
+        win.computeFrameLw(pf, df, of, cf, vf);
 
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index a0a5f5a..06f06b5 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -30,6 +30,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -102,8 +103,9 @@
 
     private boolean mUserSetupCompleted;
 
-    // User for whom this host view was created
-    private int mUserId;
+    // User for whom this host view was created.  Final because we should never change the
+    // id without reconstructing an instance of KeyguardHostView. See note below...
+    private final int mUserId;
 
     private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
 
@@ -132,10 +134,35 @@
     public KeyguardHostView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mLockPatternUtils = new LockPatternUtils(context);
+
+        // Note: This depends on KeyguardHostView getting reconstructed every time the
+        // user switches, since mUserId will be used for the entire session.
+        // Once created, keyguard should *never* re-use this instance with another user.
+        // In other words, mUserId should never change - hence it's marked final.
         mUserId = mLockPatternUtils.getCurrentUser();
-        mAppWidgetHost = new AppWidgetHost(
-                context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
-        mAppWidgetHost.setUserId(mUserId);
+
+        Context userContext = null;
+        try {
+            final String packageName = "system";
+            userContext = mContext.createPackageContextAsUser(packageName, 0,
+                    new UserHandle(mUserId));
+
+        } catch (NameNotFoundException e) {
+            e.printStackTrace();
+            // This should never happen, but it's better to have no widgets than to crash.
+            userContext = context;
+        }
+
+        // These need to be created with the user context...
+        mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
+                Looper.myLooper());
+        mAppWidgetManager = AppWidgetManager.getInstance(userContext);
+
+        cleanupAppWidgetIds();
+
+        mSecurityModel = new KeyguardSecurityModel(context);
+
+        mViewStateManager = new KeyguardViewStateManager(this);
 
         DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -355,21 +382,17 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mAppWidgetHost.startListeningAsUser(mUserId);
+        mAppWidgetHost.startListening();
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mAppWidgetHost.stopListeningAsUser(mUserId);
+        mAppWidgetHost.stopListening();
         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
     }
 
-    private AppWidgetHost getAppWidgetHost() {
-        return mAppWidgetHost;
-    }
-
     void addWidget(AppWidgetHostView view, int pageIndex) {
         mAppWidgetContainer.addWidget(view, pageIndex);
     }
@@ -1020,12 +1043,13 @@
     private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
         AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
         if (appWidgetInfo != null) {
-            AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo);
+            AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo);
             addWidget(view, pageIndex);
             return true;
         } else {
             if (updateDbIfFailed) {
-                Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting");
+                Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + "  was null for user"
+                        + mUserId + ", deleting");
                 mAppWidgetHost.deleteAppWidgetId(appId);
                 mLockPatternUtils.removeAppWidget(appId);
             }
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 1c9520d..0773afb 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -1183,6 +1183,12 @@
                 break;
             }
         }
+
+        // Disable kernel key repeat since we handle it ourselves
+        unsigned int repeatRate[] = {0,0};
+        if (ioctl(fd, EVIOCSREP, repeatRate)) {
+            ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
+        }
     }
 
     // If the device isn't recognized as something we handle, don't monitor it.
diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp
index 3c3b919..fd9c66b 100644
--- a/services/input/SpriteController.cpp
+++ b/services/input/SpriteController.cpp
@@ -210,8 +210,7 @@
                         outBuffer.width, outBuffer.height, bpr);
                 surfaceBitmap.setPixels(outBuffer.bits);
 
-                SkCanvas surfaceCanvas;
-                surfaceCanvas.setBitmapDevice(surfaceBitmap);
+                SkCanvas surfaceCanvas(surfaceBitmap);
 
                 SkPaint paint;
                 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 06aeb29..d5715a5 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -16,7 +16,7 @@
 
 package com.android.server;
 
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -121,107 +121,67 @@
         }, userFilter);
     }
 
-    /**
-     * This returns the user id of the caller, if the caller is not the system process,
-     * otherwise it assumes that the calls are from the lockscreen and hence are meant for the
-     * current user. TODO: Instead, have lockscreen make explicit calls with userId
-     */
-    private int getCallingOrCurrentUserId() {
-        int callingUid = Binder.getCallingUid();
-        // Also check the PID because Settings (power control widget) also runs as System UID
-        if (callingUid == android.os.Process.myUid()
-                && Binder.getCallingPid() == android.os.Process.myPid()) {
-            try {
-                return ActivityManagerNative.getDefault().getCurrentUser().id;
-            } catch (RemoteException re) {
-                return UserHandle.getUserId(callingUid);
-            }
-        } else {
-            return UserHandle.getUserId(callingUid);
-        }
-    }
-
     @Override
-    public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).allocateAppWidgetId(
-                packageName, hostId);
-    }
-
-    @Override
-    public int[] getAppWidgetIdsForHost(int hostId) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIdsForHost(hostId);
-    }
-    
-    @Override
-    public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).deleteAppWidgetId(appWidgetId);
-    }
-
-    @Override
-    public void deleteHost(int hostId) throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).deleteHost(hostId);
-    }
-
-    @Override
-    public void deleteAllHosts() throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).deleteAllHosts();
-    }
-
-    @Override
-    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)
+    public int allocateAppWidgetId(String packageName, int hostId, int userId)
             throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetId(appWidgetId, provider,
-                options);
+        return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
+    }
+
+    @Override
+    public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
+        return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
+    }
+
+    @Override
+    public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
+        getImplForUser(userId).deleteAppWidgetId(appWidgetId);
+    }
+
+    @Override
+    public void deleteHost(int hostId, int userId) throws RemoteException {
+        getImplForUser(userId).deleteHost(hostId);
+    }
+
+    @Override
+    public void deleteAllHosts(int userId) throws RemoteException {
+        getImplForUser(userId).deleteAllHosts();
+    }
+
+    @Override
+    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId)
+            throws RemoteException {
+        getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options);
     }
 
     @Override
     public boolean bindAppWidgetIdIfAllowed(
-            String packageName, int appWidgetId, ComponentName provider, Bundle options)
+            String packageName, int appWidgetId, ComponentName provider, Bundle options, int userId)
                     throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).bindAppWidgetIdIfAllowed(
+        return getImplForUser(userId).bindAppWidgetIdIfAllowed(
                 packageName, appWidgetId, provider, options);
     }
 
     @Override
-    public boolean hasBindAppWidgetPermission(String packageName) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).hasBindAppWidgetPermission(
-                packageName);
+    public boolean hasBindAppWidgetPermission(String packageName, int userId)
+            throws RemoteException {
+        return getImplForUser(userId).hasBindAppWidgetPermission(packageName);
     }
 
     @Override
-    public void setBindAppWidgetPermission(String packageName, boolean permission)
+    public void setBindAppWidgetPermission(String packageName, boolean permission, int userId)
             throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).setBindAppWidgetPermission(
-                packageName, permission);
+        getImplForUser(userId).setBindAppWidgetPermission(packageName, permission);
     }
 
     @Override
     public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
             int userId) throws RemoteException {
-        if (Binder.getCallingPid() != android.os.Process.myPid()
-                && userId != UserHandle.getCallingUserId()) {
-            throw new SecurityException("Call from non-system process. Calling uid = "
-                    + Binder.getCallingUid());
-        }
-        getImplForUser(userId).bindRemoteViewsService(
-                appWidgetId, intent, connection);
+        getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection);
     }
 
     @Override
     public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
-            List<RemoteViews> updatedViews) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).startListening(host,
-                packageName, hostId, updatedViews);
-    }
-
-    @Override
-    public int[] startListeningAsUser(IAppWidgetHost host, String packageName, int hostId,
             List<RemoteViews> updatedViews, int userId) throws RemoteException {
-        if (Binder.getCallingPid() != android.os.Process.myPid()
-                && userId != UserHandle.getCallingUserId()) {
-            throw new SecurityException("Call from non-system process. Calling uid = "
-                    + Binder.getCallingUid());
-        }
         return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
     }
 
@@ -250,7 +210,19 @@
         }
     }
 
+    private void checkPermission(int userId) {
+        int realUserId = ActivityManager.handleIncomingUser(
+                Binder.getCallingPid(),
+                Binder.getCallingUid(),
+                userId,
+                false, /* allowAll */
+                true, /* requireFull */
+                this.getClass().getSimpleName(),
+                this.getClass().getPackage().getName());
+    }
+
     private AppWidgetServiceImpl getImplForUser(int userId) {
+        checkPermission(userId);
         boolean sendInitial = false;
         AppWidgetServiceImpl service;
         synchronized (mAppWidgetServices) {
@@ -272,86 +244,73 @@
     }
 
     @Override
-    public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetIds(provider);
+    public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException {
+        return getImplForUser(userId).getAppWidgetIds(provider);
     }
 
     @Override
-    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetInfo(appWidgetId);
-    }
-
-    @Override
-    public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetViews(appWidgetId);
-    }
-
-    @Override
-    public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
-        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetOptions(appWidgetId, options);
-    }
-
-    @Override
-    public Bundle getAppWidgetOptions(int appWidgetId) {
-        return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
-    }
-
-    @Override
-    public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter)
+    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
             throws RemoteException {
-        return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders(categoryFilter);
+        return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
     }
 
     @Override
-    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
+    public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
+        return getImplForUser(userId).getAppWidgetViews(appWidgetId);
+    }
+
+    @Override
+    public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
+        getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
+    }
+
+    @Override
+    public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
+        return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
+    }
+
+    @Override
+    public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
             throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).notifyAppWidgetViewDataChanged(
+        return getImplForUser(userId).getInstalledProviders(categoryFilter);
+    }
+
+    @Override
+    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
+            throws RemoteException {
+        getImplForUser(userId).notifyAppWidgetViewDataChanged(
                 appWidgetIds, viewId);
     }
 
     @Override
-    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
+    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
             throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).partiallyUpdateAppWidgetIds(
+        getImplForUser(userId).partiallyUpdateAppWidgetIds(
                 appWidgetIds, views);
     }
 
     @Override
-    public void stopListening(int hostId) throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).stopListening(hostId);
-    }
-
-    @Override
-    public void stopListeningAsUser(int hostId, int userId) throws RemoteException {
-        if (Binder.getCallingPid() != android.os.Process.myPid()
-                && userId != UserHandle.getCallingUserId()) {
-            throw new SecurityException("Call from non-system process. Calling uid = "
-                    + Binder.getCallingUid());
-        }
+    public void stopListening(int hostId, int userId) throws RemoteException {
         getImplForUser(userId).stopListening(hostId);
     }
 
     @Override
     public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
             throws RemoteException {
-        if (Binder.getCallingPid() != android.os.Process.myPid()
-                && userId != UserHandle.getCallingUserId()) {
-            throw new SecurityException("Call from non-system process. Calling uid = "
-                    + Binder.getCallingUid());
-        }
         getImplForUser(userId).unbindRemoteViewsService(
                 appWidgetId, intent);
     }
 
     @Override
-    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetIds(appWidgetIds, views);
+    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
+            throws RemoteException {
+        getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views);
     }
 
     @Override
-    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
+    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId)
             throws RemoteException {
-        getImplForUser(getCallingOrCurrentUserId()).updateAppWidgetProvider(provider, views);
+        getImplForUser(userId).updateAppWidgetProvider(provider, views);
     }
 
     @Override
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index d1829ab..6eea928 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1046,7 +1046,7 @@
             if (id.host.callbacks != null) {
                 try {
                     // the lock is held, but this is a oneway call
-                    id.host.callbacks.updateAppWidget(id.appWidgetId, views);
+                    id.host.callbacks.updateAppWidget(id.appWidgetId, views, mUserId);
                 } catch (RemoteException e) {
                     // It failed; remove the callback. No need to prune because
                     // we know that this host is still referenced by this instance.
@@ -1065,7 +1065,7 @@
             if (id.host.callbacks != null) {
                 try {
                     // the lock is held, but this is a oneway call
-                    id.host.callbacks.viewDataChanged(id.appWidgetId, viewId);
+                    id.host.callbacks.viewDataChanged(id.appWidgetId, viewId, mUserId);
                 } catch (RemoteException e) {
                     // It failed; remove the callback. No need to prune because
                     // we know that this host is still referenced by this instance.
@@ -1934,7 +1934,8 @@
                                 id.views = null;
                                 if (id.host != null && id.host.callbacks != null) {
                                     try {
-                                        id.host.callbacks.providerChanged(id.appWidgetId, p.info);
+                                        id.host.callbacks.providerChanged(id.appWidgetId, p.info,
+                                                mUserId);
                                     } catch (RemoteException ex) {
                                         // It failed; remove the callback. No need to prune because
                                         // we know that this host is still referenced by this
@@ -2001,7 +2002,7 @@
             Host host = mHosts.get(i);
             try {
                 if (host.callbacks != null) {
-                    host.callbacks.providersChanged();
+                    host.callbacks.providersChanged(mUserId);
                 }
             } catch (RemoteException ex) {
                 // It failed; remove the callback. No need to prune because
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index dfde692..401a25f 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -3897,6 +3897,7 @@
                                     && !info.domain.equals(FullBackup.DATABASE_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.ROOT_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)
+                                    && !info.domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.OBB_TREE_TOKEN)
                                     && !info.domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
                                 throw new IOException("Unrecognized domain " + info.domain);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6d817a1..5e4855b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1823,6 +1823,7 @@
     }
 
     public void sendConnectedBroadcast(NetworkInfo info) {
+        enforceConnectivityInternalPermission();
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
@@ -2107,6 +2108,7 @@
 
     /** @hide */
     public void captivePortalCheckComplete(NetworkInfo info) {
+        enforceConnectivityInternalPermission();
         mNetTrackers[info.getType()].captivePortalCheckComplete();
     }
 
@@ -2365,7 +2367,7 @@
      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
      * wide use
      */
-   public void updateNetworkSettings(NetworkStateTracker nt) {
+   private void updateNetworkSettings(NetworkStateTracker nt) {
         String key = nt.getTcpBufferSizesPropName();
         String bufferSizes = key == null ? null : SystemProperties.get(key);
 
@@ -2844,7 +2846,7 @@
     }
 
     public int setUsbTethering(boolean enable) {
-        enforceTetherAccessPermission();
+        enforceTetherChangePermission();
         if (isTetheringSupported()) {
             return mTethering.setUsbTethering(enable);
         } else {
@@ -2997,6 +2999,10 @@
     }
 
     public ProxyProperties getProxy() {
+        // this information is already available as a world read/writable jvm property
+        // so this API change wouldn't have a benifit.  It also breaks the passing
+        // of proxy info to all the JVMs.
+        // enforceAccessPermission();
         synchronized (mDefaultProxyLock) {
             return mDefaultProxyDisabled ? null : mDefaultProxy;
         }
@@ -3048,6 +3054,10 @@
     }
 
     public ProxyProperties getGlobalProxy() {
+        // this information is already available as a world read/writable jvm property
+        // so this API change wouldn't have a benifit.  It also breaks the passing
+        // of proxy info to all the JVMs.
+        // enforceAccessPermission();
         synchronized (mGlobalProxyLock) {
             return mGlobalProxy;
         }
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 5e94a9f..c3f2afa 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -206,18 +206,19 @@
     /**
      * Make command for daemon, escaping arguments as needed.
      */
-    private void makeCommand(StringBuilder builder, String cmd, Object... args)
-            throws NativeDaemonConnectorException {
-        // TODO: eventually enforce that cmd doesn't contain arguments
+    private void makeCommand(StringBuilder builder, String cmd, Object... args) {
         if (cmd.indexOf('\0') >= 0) {
-            throw new IllegalArgumentException("unexpected command: " + cmd);
+            throw new IllegalArgumentException("Unexpected command: " + cmd);
+        }
+        if (cmd.indexOf(' ') >= 0) {
+            throw new IllegalArgumentException("Arguments must be separate from command");
         }
 
         builder.append(cmd);
         for (Object arg : args) {
             final String argString = String.valueOf(arg);
             if (argString.indexOf('\0') >= 0) {
-                throw new IllegalArgumentException("unexpected argument: " + arg);
+                throw new IllegalArgumentException("Unexpected argument: " + arg);
             }
 
             builder.append(' ');
@@ -240,7 +241,8 @@
 
     /**
      * Issue the given command to the native daemon and return a single expected
-     * response.
+     * response. Any arguments must be separated from base command so they can
+     * be properly escaped.
      *
      * @throws NativeDaemonConnectorException when problem communicating with
      *             native daemon, or if the response matches
@@ -274,7 +276,8 @@
     /**
      * Issue the given command to the native daemon and return any
      * {@link NativeDaemonEvent#isClassContinue()} responses, including the
-     * final terminal response.
+     * final terminal response. Any arguments must be separated from base
+     * command so they can be properly escaped.
      *
      * @throws NativeDaemonConnectorException when problem communicating with
      *             native daemon, or if the response matches
@@ -287,10 +290,11 @@
     }
 
     /**
-     * Issue the given command to the native daemon and return any
-     * {@linke NativeDaemonEvent@isClassContinue()} responses, including the
-     * final terminal response.  Note that the timeout does not count time in
-     * deep sleep.
+     * Issue the given command to the native daemon and return any {@linke
+     * NativeDaemonEvent@isClassContinue()} responses, including the final
+     * terminal response. Note that the timeout does not count time in deep
+     * sleep. Any arguments must be separated from base command so they can be
+     * properly escaped.
      *
      * @throws NativeDaemonConnectorException when problem communicating with
      *             native daemon, or if the response matches
@@ -353,51 +357,6 @@
     }
 
     /**
-     * Issue a command to the native daemon and return the raw responses.
-     *
-     * @deprecated callers should move to {@link #execute(String, Object...)}
-     *             which returns parsed {@link NativeDaemonEvent}.
-     */
-    @Deprecated
-    public ArrayList<String> doCommand(String cmd) throws NativeDaemonConnectorException {
-        final ArrayList<String> rawEvents = Lists.newArrayList();
-        final NativeDaemonEvent[] events = executeForList(cmd);
-        for (NativeDaemonEvent event : events) {
-            rawEvents.add(event.getRawEvent());
-        }
-        return rawEvents;
-    }
-
-    /**
-     * Issues a list command and returns the cooked list of all
-     * {@link NativeDaemonEvent#getMessage()} which match requested code.
-     */
-    @Deprecated
-    public String[] doListCommand(String cmd, int expectedCode)
-            throws NativeDaemonConnectorException {
-        final ArrayList<String> list = Lists.newArrayList();
-
-        final NativeDaemonEvent[] events = executeForList(cmd);
-        for (int i = 0; i < events.length - 1; i++) {
-            final NativeDaemonEvent event = events[i];
-            final int code = event.getCode();
-            if (code == expectedCode) {
-                list.add(event.getMessage());
-            } else {
-                throw new NativeDaemonConnectorException(
-                        "unexpected list response " + code + " instead of " + expectedCode);
-            }
-        }
-
-        final NativeDaemonEvent finalEvent = events[events.length - 1];
-        if (!finalEvent.isClassOk()) {
-            throw new NativeDaemonConnectorException("unexpected final event: " + finalEvent);
-        }
-
-        return list.toArray(new String[list.size()]);
-    }
-
-    /**
      * Append the given argument to {@link StringBuilder}, escaping as needed,
      * and surrounding with quotes when it contains spaces.
      */
@@ -444,7 +403,8 @@
     }
 
     /**
-     * Command builder that handles argument list building.
+     * Command builder that handles argument list building. Any arguments must
+     * be separated from base command so they can be properly escaped.
      */
     public static class Command {
         private String mCmd;
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 25ed27a..5630b08 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -25,8 +25,6 @@
 import static android.net.TrafficStats.UID_TETHERING;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceRxThrottleResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceTxThrottleResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
@@ -121,8 +119,6 @@
         public static final int SoftapStatusResult        = 214;
         public static final int InterfaceRxCounterResult  = 216;
         public static final int InterfaceTxCounterResult  = 217;
-        public static final int InterfaceRxThrottleResult = 218;
-        public static final int InterfaceTxThrottleResult = 219;
         public static final int QuotaCounterResult        = 220;
         public static final int TetheringStatsResult      = 221;
         public static final int DnsProxyQueryResult       = 222;
@@ -836,31 +832,28 @@
     }
 
     // TODO(BT) Remove
-    public void startReverseTethering(String iface)
-             throws IllegalStateException {
-        if (DBG) Slog.d(TAG, "startReverseTethering in");
+    @Override
+    public void startReverseTethering(String iface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         // cmd is "tether start first_start first_stop second_start second_stop ..."
         // an odd number of addrs will fail
-        String cmd = "tether start-reverse";
-        cmd += " " + iface;
-        if (DBG) Slog.d(TAG, "startReverseTethering cmd: " + cmd);
         try {
-            mConnector.doCommand(cmd);
+            mConnector.execute("tether", "start-reverse", iface);
         } catch (NativeDaemonConnectorException e) {
-            throw new IllegalStateException("Unable to communicate to native daemon");
+            throw e.rethrowAsParcelableException();
         }
         BluetoothTetheringDataTracker.getInstance().startReverseTether(iface);
 
     }
 
     // TODO(BT) Remove
-    public void stopReverseTethering() throws IllegalStateException {
+    @Override
+    public void stopReverseTethering() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            mConnector.doCommand("tether stop-reverse");
+            mConnector.execute("tether", "stop-reverse");
         } catch (NativeDaemonConnectorException e) {
-            throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
+            throw e.rethrowAsParcelableException();
         }
         BluetoothTetheringDataTracker.getInstance().stopReverseTether();
     }
@@ -1506,6 +1499,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void monitor() {
         if (mConnector != null) {
             mConnector.monitor();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 949c2ed..8ef247e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -62,6 +62,7 @@
 import com.android.server.power.ShutdownThread;
 import com.android.server.search.SearchManagerService;
 import com.android.server.usb.UsbService;
+import com.android.server.wifi.WifiService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9c518a1..fd5e79a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -934,12 +934,10 @@
      * @param service The service.
      * @return True if the service was removed, false otherwise.
      */
-    private void removeServiceLocked(Service service) {
-        UserState userState = getUserStateLocked(service.mUserId);
+    private void removeServiceLocked(Service service, UserState userState) {
         userState.mBoundServices.remove(service);
         userState.mComponentNameToServiceMap.remove(service.mComponentName);
         service.unlinkToOwnDeath();
-        service.dispose();
     }
 
     /**
@@ -1672,11 +1670,9 @@
         public boolean bindLocked() {
             UserState userState = getUserStateLocked(mUserId);
             if (!mIsAutomation) {
-                if (mService == null) {
-                    if (mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE,
-                            new UserHandle(mUserId))) {
-                        userState.mBindingServices.add(mComponentName);
-                    }
+                if (mService == null && mContext.bindServiceAsUser(
+                        mIntent, this, Context.BIND_AUTO_CREATE, new UserHandle(mUserId))) {
+                    userState.mBindingServices.add(mComponentName);
                 }
             } else {
                 userState.mBindingServices.add(mComponentName);
@@ -1697,14 +1693,15 @@
             if (mService == null) {
                 return false;
             }
+            UserState userState = getUserStateLocked(mUserId);
             if (!mIsAutomation) {
                 mContext.unbindService(this);
             } else {
-                UserState userState = getUserStateLocked(mUserId);
                 userState.mUiAutomationService = null;
                 userState.mUiAutomationServiceClient = null;
             }
-            removeServiceLocked(this);
+            removeServiceLocked(this, userState);
+            dispose();
             return true;
         }
 
@@ -1750,11 +1747,11 @@
                 mService = service;
                 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
                 UserState userState = getUserStateLocked(mUserId);
+                addServiceLocked(this, userState);
                 if (!userState.mBindingServices.contains(mComponentName)) {
                     binderDied();
                 } else {
                     userState.mBindingServices.remove(mComponentName);
-                    addServiceLocked(this, userState);
                     onUserStateChangedLocked(userState);
                 }
             }
@@ -2106,9 +2103,10 @@
 
         public void binderDied() {
             synchronized (mLock) {
-                // The death recipient is unregistered in tryRemoveServiceLocked
-                removeServiceLocked(this);
                 UserState userState = getUserStateLocked(mUserId);
+                // The death recipient is unregistered in removeServiceLocked
+                removeServiceLocked(this, userState);
+                dispose();
                 if (mIsAutomation) {
                     // We no longer have an automation service, so restore
                     // the state based on values in the settings database.
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index f2d401f..a2f3372 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -471,6 +471,7 @@
     void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
         if (inHistory && !finishing) {
             if (task != null) {
+                // TODO: If this is the last ActivityRecord in task, remove from ActivityStack.
                 task.removeActivity(this);
                 task.numActivities--;
             }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a18a0d1..dfbf3b3 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -77,7 +77,6 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
-import java.util.NoSuchElementException;
 
 /**
  * State and management of a single stack of activities.
@@ -142,9 +141,6 @@
     // is being started.
     static final boolean SHOW_APP_STARTING_PREVIEW = true;
 
-    static final boolean FORWARD_ITERATOR = false;
-    static final boolean REVERSE_ITERATOR = true;
-
     enum ActivityState {
         INITIALIZING,
         RESUMED,
@@ -307,12 +303,6 @@
      */
     boolean mDismissKeyguardOnNextActivity = false;
 
-    /** So we don't have to keep constructing a new object for utility non-nested use. */
-    final ActivityIterator mTmpActivityIterator = new ActivityIterator(FORWARD_ITERATOR, true);
-
-    /** So we don't have to keep constructing a new object for utility non-nested use. */
-    final TaskIterator mTmpTaskIterator = new TaskIterator();
-
     /**
      * Save the most recent screenshot for reuse. This keeps Recents from taking two identical
      * screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
@@ -355,6 +345,8 @@
 
     final Handler mHandler;
 
+    String mLastHistoryModifier;
+
     final class ActivityStackHandler extends Handler {
         //public Handler() {
         //    if (localLOGV) Slog.v(TAG, "Handler started!");
@@ -481,26 +473,66 @@
     }
 
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
+        ActivityRecord newAr = newTopRunningActivityLocked(notTop);
+
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
             if (!r.finishing && r != notTop && okToShow(r)) {
+                if (VALIDATE_TASK_REPLACE && newAr != r) logHistories(
+                        "topRunningActivityLocked", true);
                 return r;
             }
             i--;
         }
+        if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
+                "topRunningActivityLocked: mismatch: newAr!=null");
+        return null;
+    }
+
+    final ActivityRecord newTopRunningActivityLocked(ActivityRecord notTop) {
+        for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
+            final TaskRecord task = mTaskHistory.get(i);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int j = activities.size() - 1; j >= 0; --j) {
+                ActivityRecord r = activities.get(j);
+                if (!r.finishing && r != notTop && okToShow(r)) {
+                    return r;
+                }
+            }
+        }
         return null;
     }
 
     final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
+        ActivityRecord newAr = newTopRunningNonDelayedActivityLocked(notTop);
+
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
             if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
+                if (VALIDATE_TASK_REPLACE && newAr != r) Slog.w(TAG,
+                    "topRunningNonDelayedActivityLocked: mismatch: newAr=" + newAr + " r=" + r);
                 return r;
             }
             i--;
         }
+        if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
+                "topRunningNonDelayedActivityLocked: mismatch: newAr!=null");
+        return null;
+    }
+
+    final ActivityRecord newTopRunningNonDelayedActivityLocked(ActivityRecord notTop) {
+        for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
+            final TaskRecord task = mTaskHistory.get(i);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int j = activities.size() - 1; j >= 0; --j) {
+                ActivityRecord r = activities.get(j);
+                if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
+                    return r;
+                }
+            }
+        }
         return null;
     }
 
@@ -514,16 +546,40 @@
      * @return Returns the HistoryRecord of the next activity on the stack.
      */
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
+        ActivityRecord newAr = newTopRunningActivityLocked(token, taskId);
+
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
             // Note: the taskId check depends on real taskId fields being non-zero
             if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
                     && okToShow(r)) {
+                if (VALIDATE_TASK_REPLACE && newAr != r) Slog.w(TAG,
+                        "topRunningActivityLocked(token): mismatch: newAr=" + newAr + " r=" + r);
                 return r;
             }
             i--;
         }
+        if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
+                "topRunningActivityLocked(token): mismatch: newAr!=null");
+        return null;
+    }
+
+    final ActivityRecord newTopRunningActivityLocked(IBinder token, int taskId) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.taskId == taskId) {
+                continue;
+            }
+            ArrayList<ActivityRecord> activities = task.mActivities;
+            for (int i = activities.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = activities.get(i);
+                // Note: the taskId check depends on real taskId fields being non-zero
+                if (!r.finishing && (token != r.appToken) && okToShow(r)) {
+                    return r;
+                }
+            }
+        }
         return null;
     }
 
@@ -1001,12 +1057,11 @@
             mGoingToSleep.release();
         }
         // Ensure activities are no longer sleeping.
-        if (VALIDATE_TASK_REPLACE) {
-            verifyActivityRecords();
-        }
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            r.setSleeping(false);
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                activities.get(activityNdx).setSleeping(false);
+            }
         }
         mGoingToSleepActivities.clear();
     }
@@ -1049,12 +1104,15 @@
             // Make sure any stopped but visible activities are now sleeping.
             // This ensures that the activity's onStop() is called.
             if (VALIDATE_TASK_REPLACE) {
-                verifyActivityRecords();
+                verifyActivityRecords(true);
             }
-            for (int i=mHistory.size()-1; i>=0; i--) {
-                ActivityRecord r = mHistory.get(i);
-                if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
-                    r.setSleeping(true);
+            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+                final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                    final ActivityRecord r = activities.get(activityNdx);
+                    if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
+                        r.setSleeping(true);
+                    }
                 }
             }
 
@@ -1192,15 +1250,9 @@
     }
 
     final void activityResumed(IBinder token) {
-        ActivityRecord r = null;
-
         synchronized (mService) {
-            if (VALIDATE_TASK_REPLACE) {
-                verifyActivityRecords();
-            }
-            int index = indexOfTokenLocked(token);
-            if (index >= 0) {
-                r = mHistory.get(index);
+            final ActivityRecord r = isInStackLocked(token);
+            if (r != null) {
                 if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
                 r.icicle = null;
                 r.haveState = false;
@@ -1212,15 +1264,9 @@
         if (DEBUG_PAUSE) Slog.v(
             TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
 
-        ActivityRecord r = null;
-
         synchronized (mService) {
-            if (VALIDATE_TASK_REPLACE) {
-                verifyActivityRecords();
-            }
-            int index = indexOfTokenLocked(token);
-            if (index >= 0) {
-                r = mHistory.get(index);
+            final ActivityRecord r = isInStackLocked(token);
+            if (r != null) {
                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                 if (mPausingActivity == r) {
                     if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
@@ -1431,108 +1477,97 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         if (VALIDATE_TASK_REPLACE) {
-            verifyActivityRecords();
+            verifyActivityRecords(true);
         }
-        final int count = mHistory.size();
-        int i = count-1;
-        while (mHistory.get(i) != top) {
-            i--;
-        }
-        ActivityRecord r;
+        boolean aboveTop = true;
         boolean behindFullscreen = false;
-        for (; i>=0; i--) {
-            r = mHistory.get(i);
-            if (DEBUG_VISBILITY) Slog.v(
-                    TAG, "Make visible? " + r + " finishing=" + r.finishing
-                    + " state=" + r.state);
-            if (r.finishing) {
-                continue;
-            }
-            
-            final boolean doThisProcess = onlyThisProcess == null
-                    || onlyThisProcess.equals(r.processName);
-            
-            // First: if this is not the current activity being started, make
-            // sure it matches the current configuration.
-            if (r != starting && doThisProcess) {
-                ensureActivityConfigurationLocked(r, 0);
-            }
-            
-            if (r.app == null || r.app.thread == null) {
-                if (onlyThisProcess == null
-                        || onlyThisProcess.equals(r.processName)) {
-                    // This activity needs to be visible, but isn't even
-                    // running...  get it started, but don't resume it
-                    // at this point.
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.finishing) {
+                    continue;
+                }
+                if (aboveTop && r != top) {
+                    continue;
+                }
+                aboveTop = false;
+                if (!behindFullscreen) {
                     if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Start and freeze screen for " + r);
-                    if (r != starting) {
-                        r.startFreezingScreenLocked(r.app, configChanges);
+                            TAG, "Make visible? " + r + " finishing=" + r.finishing
+                            + " state=" + r.state);
+                    
+                    final boolean doThisProcess = onlyThisProcess == null
+                            || onlyThisProcess.equals(r.processName);
+
+                    // First: if this is not the current activity being started, make
+                    // sure it matches the current configuration.
+                    if (r != starting && doThisProcess) {
+                        ensureActivityConfigurationLocked(r, 0);
                     }
-                    if (!r.visible) {
+
+                    if (r.app == null || r.app.thread == null) {
+                        if (onlyThisProcess == null
+                                || onlyThisProcess.equals(r.processName)) {
+                            // This activity needs to be visible, but isn't even
+                            // running...  get it started, but don't resume it
+                            // at this point.
+                            if (DEBUG_VISBILITY) Slog.v(
+                                    TAG, "Start and freeze screen for " + r);
+                            if (r != starting) {
+                                r.startFreezingScreenLocked(r.app, configChanges);
+                            }
+                            if (!r.visible) {
+                                if (DEBUG_VISBILITY) Slog.v(
+                                        TAG, "Starting and making visible: " + r);
+                                mService.mWindowManager.setAppVisibility(r.appToken, true);
+                            }
+                            if (r != starting) {
+                                startSpecificActivityLocked(r, false, false);
+                            }
+                        }
+
+                    } else if (r.visible) {
+                        // If this activity is already visible, then there is nothing
+                        // else to do here.
                         if (DEBUG_VISBILITY) Slog.v(
-                                TAG, "Starting and making visible: " + r);
-                        mService.mWindowManager.setAppVisibility(r.appToken, true);
-                    }
-                    if (r != starting) {
-                        startSpecificActivityLocked(r, false, false);
-                    }
-                }
-
-            } else if (r.visible) {
-                // If this activity is already visible, then there is nothing
-                // else to do here.
-                if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Skipping: already visible at " + r);
-                r.stopFreezingScreenLocked(false);
-
-            } else if (onlyThisProcess == null) {
-                // This activity is not currently visible, but is running.
-                // Tell it to become visible.
-                r.visible = true;
-                if (r.state != ActivityState.RESUMED && r != starting) {
-                    // If this activity is paused, tell it
-                    // to now show its window.
-                    if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Making visible and scheduling visibility: " + r);
-                    try {
-                        mService.mWindowManager.setAppVisibility(r.appToken, true);
-                        r.sleeping = false;
-                        r.app.pendingUiClean = true;
-                        r.app.thread.scheduleWindowVisibility(r.appToken, true);
+                                TAG, "Skipping: already visible at " + r);
                         r.stopFreezingScreenLocked(false);
-                    } catch (Exception e) {
-                        // Just skip on any failure; we'll make it
-                        // visible when it next restarts.
-                        Slog.w(TAG, "Exception thrown making visibile: "
-                                + r.intent.getComponent(), e);
+
+                    } else if (onlyThisProcess == null) {
+                        // This activity is not currently visible, but is running.
+                        // Tell it to become visible.
+                        r.visible = true;
+                        if (r.state != ActivityState.RESUMED && r != starting) {
+                            // If this activity is paused, tell it
+                            // to now show its window.
+                            if (DEBUG_VISBILITY) Slog.v(
+                                    TAG, "Making visible and scheduling visibility: " + r);
+                            try {
+                                mService.mWindowManager.setAppVisibility(r.appToken, true);
+                                r.sleeping = false;
+                                r.app.pendingUiClean = true;
+                                r.app.thread.scheduleWindowVisibility(r.appToken, true);
+                                r.stopFreezingScreenLocked(false);
+                            } catch (Exception e) {
+                                // Just skip on any failure; we'll make it
+                                // visible when it next restarts.
+                                Slog.w(TAG, "Exception thrown making visibile: "
+                                        + r.intent.getComponent(), e);
+                            }
+                        }
                     }
-                }
-            }
 
-            // Aggregate current change flags.
-            configChanges |= r.configChangeFlags;
+                    // Aggregate current change flags.
+                    configChanges |= r.configChangeFlags;
 
-            if (r.fullscreen) {
-                // At this point, nothing else needs to be shown
-                if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Stopping: fullscreen at " + r);
-                behindFullscreen = true;
-                i--;
-                break;
-            }
-        }
-
-        // Now for any activities that aren't visible to the user, make
-        // sure they no longer are keeping the screen frozen.
-        while (i >= 0) {
-            r = mHistory.get(i);
-            if (DEBUG_VISBILITY) Slog.v(
-                    TAG, "Make invisible? " + r + " finishing=" + r.finishing
-                    + " state=" + r.state
-                    + " behindFullscreen=" + behindFullscreen);
-            if (!r.finishing) {
-                if (behindFullscreen) {
+                    if (r.fullscreen) {
+                        // At this point, nothing else needs to be shown
+                        if (DEBUG_VISBILITY) Slog.v(
+                                TAG, "Stopping: fullscreen at " + r);
+                        behindFullscreen = true;
+                    }
+                } else {
                     if (r.visible) {
                         if (DEBUG_VISBILITY) Slog.v(
                                 TAG, "Making invisible: " + r);
@@ -1556,13 +1591,8 @@
                         if (DEBUG_VISBILITY) Slog.v(
                                 TAG, "Already invisible: " + r);
                     }
-                } else if (r.fullscreen) {
-                    if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Now behindFullscreen: " + r);
-                    behindFullscreen = true;
                 }
             }
-            i--;
         }
     }
 
@@ -1969,8 +1999,15 @@
         return true;
     }
 
+    /** Temporary until startActivityLocked is rewritten for tasks. */
+    private int convertAddPos(int addPos) {
+        final ActivityRecord r = mHistory.get(addPos);
+        return r.task.mActivities.indexOf(r);
+    }
+
     private final void startActivityLocked(ActivityRecord r, boolean newTask,
             boolean doResume, boolean keepCurTransition, Bundle options) {
+        mLastHistoryModifier = "startActivityLocked";
         final int NH = mHistory.size();
 
         int addPos = -1;
@@ -1998,11 +2035,12 @@
                         r.task.addActivityToTop(r);
                         mHistory.add(addPos, r);
                         r.putInHistory();
-                        mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
-                                r.info.screenOrientation, r.fullscreen,
+                        mService.mWindowManager.addAppToken(convertAddPos(addPos), r.appToken,
+                                r.task.taskId, r.info.screenOrientation, r.fullscreen,
                                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
+                            verifyActivityRecords(true);
                         }
                         ActivityOptions.abort(options);
                         return;
@@ -2039,6 +2077,11 @@
         mHistory.add(addPos, r);
         r.putInHistory();
         r.frontOfTask = newTask;
+        if (VALIDATE_TASK_REPLACE) {
+            if (verifyActivityRecords(false)) {
+                Slog.w(TAG, "startActivityLocked: addPos=" + addPos);
+            }
+        }
         if (NH > 0) {
             // We want to show the starting preview window if we are
             // switching to a new task, or the next activity's process is
@@ -2064,8 +2107,8 @@
                 mNoAnimActivities.remove(r);
             }
             r.updateOptionsLocked(options);
-            mService.mWindowManager.addAppToken(
-                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+            mService.mWindowManager.addAppToken(convertAddPos(addPos),
+                    r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
             boolean doShow = true;
             if (newTask) {
@@ -2103,7 +2146,7 @@
         } else {
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
-            mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
+            mService.mWindowManager.addAppToken(convertAddPos(addPos), r.appToken, r.task.taskId,
                     r.info.screenOrientation, r.fullscreen,
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
             ActivityOptions.abort(options);
@@ -2116,7 +2159,9 @@
             resumeTopActivityLocked(null);
         }
         if (VALIDATE_TASK_REPLACE) {
-            verifyActivityRecords();
+            if (verifyActivityRecords(true)) {
+                Slog.w(TAG, "startActivityLocked: addPos=" + addPos);
+            }
         }
     }
 
@@ -2142,8 +2187,10 @@
      * Perform a reset of the given task, if needed as part of launching it.
      * Returns the new HistoryRecord at the top of the task.
      */
-    private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
+/*    private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
             ActivityRecord newActivity) {
+        mLastHistoryModifier = "resetTaskIfNeededLocked";
+
         boolean forceReset = (newActivity.info.flags
                 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
         if (ACTIVITY_INACTIVE_RESET_TIME > 0
@@ -2281,6 +2328,7 @@
                             dstPos++;
                             i++;
                         }
+                        rebuildTaskHistory();
                         mService.mWindowManager.moveTaskToBottom(taskId);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
@@ -2429,6 +2477,7 @@
                                 + " in to resetting task " + task);
                         mService.mWindowManager.setAppGroupId(p.appToken, taskId);
                     }
+                    rebuildTaskHistory();
                     // TODO: This is wrong because it doesn't take lastReparentPos into account.
                     mService.mWindowManager.moveTaskToTop(taskId);
                     if (VALIDATE_TOKENS) {
@@ -2478,11 +2527,345 @@
         }
 
         if (VALIDATE_TASK_REPLACE) {
-            verifyActivityRecords();
+            verifyActivityRecords(true);
         }
         return taskTop;
     }
-    
+*/
+    /**
+     * Helper method for #resetTaskIfNeededLocked.
+     * We are inside of the task being reset...  we'll either finish this activity, push it out
+     * for another task, or leave it as-is.
+     * @param task The task containing the Activity (taskTop) that might be reset.
+     * @param forceReset
+     * @return An ActivityOptions that needs to be processed.
+     */
+    private final ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task,
+            boolean forceReset) {
+        ActivityOptions topOptions = null;
+
+        int replyChainEnd = -1;
+        boolean canMoveOptions = true;
+
+        // We only do this for activities that are not the root of the task (since if we finish
+        // the root, we may no longer have the task!).
+        final ArrayList<ActivityRecord> activities = task.mActivities;
+        final int numActivities = activities.size();
+        for (int i = numActivities - 1; i > 0; --i ) {
+            ActivityRecord target = activities.get(i);
+
+            final int flags = target.info.flags;
+            final boolean finishOnTaskLaunch =
+                    (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
+            final boolean allowTaskReparenting =
+                    (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
+            final boolean clearWhenTaskReset =
+                    (target.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
+
+            if (!finishOnTaskLaunch
+                    && !clearWhenTaskReset
+                    && target.resultTo != null) {
+                // If this activity is sending a reply to a previous
+                // activity, we can't do anything with it now until
+                // we reach the start of the reply chain.
+                // XXX note that we are assuming the result is always
+                // to the previous activity, which is almost always
+                // the case but we really shouldn't count on.
+                if (replyChainEnd < 0) {
+                    replyChainEnd = i;
+                }
+            } else if (!finishOnTaskLaunch
+                    && !clearWhenTaskReset
+                    && allowTaskReparenting
+                    && target.taskAffinity != null
+                    && !target.taskAffinity.equals(task.affinity)) {
+                // If this activity has an affinity for another
+                // task, then we need to move it out of here.  We will
+                // move it as far out of the way as possible, to the
+                // bottom of the activity stack.  This also keeps it
+                // correctly ordered with any activities we previously
+                // moved.
+                TaskRecord bottomTask = mTaskHistory.get(0);
+                ActivityRecord p = bottomTask.mActivities.get(0);
+                if (target.taskAffinity != null
+                        && target.taskAffinity.equals(p.task.affinity)) {
+                    // If the activity currently at the bottom has the
+                    // same task affinity as the one we are moving,
+                    // then merge it into the same task.
+                    if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                        "resetTaskFoundIntended: would reparenting " + target + " to bottom " + p.task);
+                    target.setTask(p.task, p.thumbHolder, false);
+                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                            + " out to bottom task " + p.task);
+                } else {
+                    do {
+                        mService.mCurTask++;
+                        if (mService.mCurTask <= 0) {
+                            mService.mCurTask = 1;
+                        }
+                    } while (mTaskIdToTaskRecord.get(mService.mCurTask) != null);
+                    target.setTask(createTaskRecord(mService.mCurTask, target.info, null, false),
+                            null, false);
+                    target.task.affinityIntent = target.intent;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                            + " out to new task " + target.task);
+                }
+
+                final TaskRecord targetTask = target.task;
+                final int targetTaskId = targetTask.taskId;
+                mService.mWindowManager.setAppGroupId(target.appToken, targetTaskId);
+
+                ThumbnailHolder curThumbHolder = target.thumbHolder;
+                boolean gotOptions = !canMoveOptions;
+
+                final int start = replyChainEnd < 0 ? i : replyChainEnd;
+                for (int srcPos = start; srcPos >= i; --srcPos) {
+                    p = activities.get(srcPos);
+                    if (p.finishing) {
+                        continue;
+                    }
+
+                    curThumbHolder = p.thumbHolder;
+                    canMoveOptions = false;
+                    if (!gotOptions && topOptions == null) {
+                        topOptions = p.takeOptionsLocked();
+                        if (topOptions != null) {
+                            gotOptions = true;
+                        }
+                    }
+                    if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
+                            + task + " adding to task=" + targetTask,
+                            new RuntimeException("here").fillInStackTrace());
+                    if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
+                            + " out to target's task " + target.task);
+                    p.setTask(targetTask, curThumbHolder, false);
+                    targetTask.addActivityAtBottom(p);
+                    mHistory.remove(p);
+                    mHistory.add(0, p);
+                    mService.mWindowManager.setAppGroupId(p.appToken, targetTaskId);
+                }
+
+                mService.mWindowManager.moveTaskToBottom(targetTaskId);
+                if (VALIDATE_TOKENS) {
+                    validateAppTokensLocked();
+                }
+
+                replyChainEnd = -1;
+            } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
+                // If the activity should just be removed -- either
+                // because it asks for it, or the task should be
+                // cleared -- then finish it and anything that is
+                // part of its reply chain.
+                int end;
+                if (clearWhenTaskReset) {
+                    // In this case, we want to finish this activity
+                    // and everything above it, so be sneaky and pretend
+                    // like these are all in the reply chain.
+                    end = numActivities - 1;
+                } else if (replyChainEnd < 0) {
+                    end = i;
+                } else {
+                    end = replyChainEnd;
+                }
+                ActivityRecord p = null;
+                boolean gotOptions = !canMoveOptions;
+                for (int srcPos = i; srcPos <= end; srcPos++) {
+                    p = activities.get(srcPos);
+                    if (p.finishing) {
+                        continue;
+                    }
+                    canMoveOptions = false;
+                    if (!gotOptions && topOptions == null) {
+                        topOptions = p.takeOptionsLocked();
+                        if (topOptions != null) {
+                            gotOptions = true;
+                        }
+                    }
+                    if (DEBUG_TASKS || VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                            "resetTaskIntendedTask: would call finishActivity on " + p);
+                    if (finishActivityLocked(p, Activity.RESULT_CANCELED, null, "reset", false)) {
+                        end--;
+                        srcPos--;
+                    }
+                }
+                replyChainEnd = -1;
+            } else {
+                // If we were in the middle of a chain, well the
+                // activity that started it all doesn't want anything
+                // special, so leave it all as-is.
+                replyChainEnd = -1;
+            }
+        }
+
+        return topOptions;
+    }
+
+    /**
+     * Helper method for #resetTaskIfNeededLocked. Processes all of the activities in a given
+     * TaskRecord looking for an affinity with the task of resetTaskIfNeededLocked.taskTop.
+     * @param affinityTask The task we are looking for an affinity to.
+     * @param task Task that resetTaskIfNeededLocked.taskTop belongs to.
+     * @param topTaskIsHigher True if #task has already been processed by resetTaskIfNeededLocked.
+     * @param forceReset Flag passed in to resetTaskIfNeededLocked.
+     */
+    private final void resetAffinityTaskIfNeededLocked(TaskRecord affinityTask, TaskRecord task,
+            boolean topTaskIsHigher, boolean forceReset
+            , ActivityRecord taskTop
+            ) {
+        int replyChainEnd = -1;
+        final int taskId = task.taskId;
+        final String taskAffinity = task.affinity;
+
+        final ArrayList<ActivityRecord> activities = affinityTask.mActivities;
+        final int numActivities = activities.size();
+        // Do not operate on the root Activity.
+        for (int i = numActivities - 1; i > 0; --i) {
+            ActivityRecord target = activities.get(i);
+
+            final int flags = target.info.flags;
+            boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
+            boolean allowTaskReparenting = (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
+
+            if (target.resultTo != null) {
+                // If this activity is sending a reply to a previous
+                // activity, we can't do anything with it now until
+                // we reach the start of the reply chain.
+                // XXX note that we are assuming the result is always
+                // to the previous activity, which is almost always
+                // the case but we really shouldn't count on.
+                if (replyChainEnd < 0) {
+                    replyChainEnd = i;
+                }
+            } else if (topTaskIsHigher
+                    && allowTaskReparenting
+                    && taskAffinity != null
+                    && taskAffinity.equals(target.taskAffinity)) {
+                // This activity has an affinity for our task. Either remove it if we are
+                // clearing or move it over to our task.  Note that
+                // we currently punt on the case where we are resetting a
+                // task that is not at the top but who has activities above
+                // with an affinity to it...  this is really not a normal
+                // case, and we will need to later pull that task to the front
+                // and usually at that point we will do the reset and pick
+                // up those remaining activities.  (This only happens if
+                // someone starts an activity in a new task from an activity
+                // in a task that is not currently on top.)
+                if (forceReset || finishOnTaskLaunch) {
+                    final int start = replyChainEnd >= 0 ? replyChainEnd : i;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index " + start + " to " + i);
+                    for (int srcPos = start; srcPos >= i; --srcPos) {
+                        final ActivityRecord p = activities.get(srcPos);
+                        if (p.finishing) {
+                            continue;
+                        }
+                        if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                                "resetAffinityTaskIfNeededLocked: calling finishActivity on " + p);
+                        finishActivityLocked(p, Activity.RESULT_CANCELED, null, "reset", false);
+                    }
+                } else {
+                    int taskTopI = mHistory.indexOf(taskTop);
+                    final int end = replyChainEnd >= 0 ? replyChainEnd : i;
+                    if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index " + i + " to " + end);
+                    for (int srcPos = i; srcPos <= end; ++srcPos) {
+                        final ActivityRecord p = activities.get(srcPos);
+                        if (p.finishing) {
+                            continue;
+                        }
+                        p.setTask(task, null, false);
+                        task.addActivityToTop(p);
+
+                        mHistory.remove(p);
+                        mHistory.add(taskTopI--, p);
+
+                        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p
+                                + " to stack at " + task,
+                                new RuntimeException("here").fillInStackTrace());
+                        if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " from " + srcPos
+                                + " in to resetting task " + task);
+                        mService.mWindowManager.setAppGroupId(p.appToken, taskId);
+                    }
+                    mService.mWindowManager.moveTaskToTop(taskId);
+                    if (VALIDATE_TOKENS) {
+                        validateAppTokensLocked();
+                    }
+                    if (VALIDATE_TASK_REPLACE) {
+                        verifyActivityRecords(false);
+                    }
+
+                    // Now we've moved it in to place...  but what if this is
+                    // a singleTop activity and we have put it on top of another
+                    // instance of the same activity?  Then we drop the instance
+                    // below so it remains singleTop.
+                    if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
+                        ArrayList<ActivityRecord> taskActivities = task.mActivities;
+                        boolean found = false;
+                        int targetNdx = taskActivities.indexOf(target);
+                        if (targetNdx > 0) {
+                            ActivityRecord p = taskActivities.get(targetNdx - 1);
+                            if (p.intent.getComponent().equals(target.intent.getComponent())) {
+                                if (finishActivityLocked(p, Activity.RESULT_CANCELED, null, "replace",
+                                        false)) {
+                                    taskTopI--;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                replyChainEnd = -1;
+            }
+        }
+    }
+
+    private final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop,
+            ActivityRecord newActivity) {
+        boolean forceReset =
+                (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
+        if (ACTIVITY_INACTIVE_RESET_TIME > 0
+                && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
+            if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
+                forceReset = true;
+            }
+        }
+
+        final TaskRecord task = taskTop.task;
+
+        /** False until we evaluate the TaskRecord associated with taskTop. Switches to true
+         * for remaining tasks. Used for later tasks to reparent to task. */
+        boolean taskFound = false;
+
+        /** If ActivityOptions are moved out and need to be aborted or moved to taskTop. */
+        ActivityOptions topOptions = null;
+
+        for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
+            final TaskRecord targetTask = mTaskHistory.get(i);
+
+            if (targetTask == task) {
+                topOptions = resetTargetTaskIfNeededLocked(task, forceReset);
+                taskFound = true;
+            } else {
+                resetAffinityTaskIfNeededLocked(targetTask, task, taskFound, forceReset, taskTop);
+            }
+        }
+
+        taskTop = task.getTopActivity();
+        if (topOptions != null) {
+            // If we got some ActivityOptions from an activity on top that
+            // was removed from the task, propagate them to the new real top.
+            if (taskTop != null) {
+                if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                    "newResetTaskIfNeededLocked: would call updateOptionsLocked " + topOptions);
+                taskTop.updateOptionsLocked(topOptions);
+            } else {
+                if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+                    "newResetTaskIfNeededLocked: would call " + topOptions + " abort");
+                topOptions.abort();
+            }
+        }
+
+        return taskTop;
+    }
+
     /**
      * Perform clear operation as requested by
      * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
@@ -2534,8 +2917,8 @@
                     if (opts != null) {
                         ret.updateOptionsLocked(opts);
                     }
-                    if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "clear", false)) {
+                    if (finishActivityLocked(r, Activity.RESULT_CANCELED, null,
+                            "clear", false)) {
                         i--;
                     }
                 }
@@ -2548,8 +2931,8 @@
                     if (!ret.finishing) {
                         int index = mHistory.indexOf(ret);
                         if (index >= 0) {
-                            finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
-                                    null, "clear", false);
+                            finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
+                                    "clear", false);
                         }
                         return null;
                     }
@@ -2577,8 +2960,8 @@
                 i++;
                 continue;
             }
-            if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                    null, "clear", false)) {
+            if (!finishActivityLocked(r, Activity.RESULT_CANCELED, null,
+                    "clear", false)) {
                 i++;
             }
         }
@@ -2644,6 +3027,7 @@
      */
     private final ActivityRecord moveActivityToFrontLocked(int where) {
         ActivityRecord newTop = mHistory.remove(where);
+        newMoveActivityToFrontLocked(newTop);
         int top = mHistory.size();
         ActivityRecord oldTop = mHistory.get(top-1);
         if (DEBUG_ADD_REMOVE) {
@@ -2653,6 +3037,17 @@
                     + top, here);
         }
         mHistory.add(top, newTop);
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
+        return newTop;
+    }
+
+    private final ActivityRecord newMoveActivityToFrontLocked(ActivityRecord newTop) {
+        final TaskRecord task = newTop.task;
+        ActivityRecord oldTop = task.getTopActivity();
+        task.mActivities.remove(newTop);
+        task.mActivities.add(newTop);
         oldTop.frontOfTask = false;
         newTop.frontOfTask = true;
         return newTop;
@@ -2663,6 +3058,7 @@
             String resultWho, int requestCode,
             int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
             boolean componentSpecified, ActivityRecord[] outActivity) {
+        mLastHistoryModifier = "startActivityLocked(IApplicationThread)";
 
         int err = ActivityManager.START_SUCCESS;
 
@@ -3701,8 +4097,7 @@
             }
 
             // Get the activity record.
-            int index = mHistory.indexOf(r);
-            if (index >= 0) {
+            if (isInStackLocked(token) != null) {
                 res = r;
 
                 if (fromTimeout) {
@@ -3851,7 +4246,7 @@
         }
         ActivityRecord r = mHistory.get(index);
 
-        finishActivityLocked(r, index, resultCode, resultData, reason, oomAdj);
+        finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
         return true;
     }
 
@@ -3867,8 +4262,8 @@
             if (r.resultTo == self && r.requestCode == requestCode) {
                 if ((r.resultWho == null && resultWho == null) ||
                     (r.resultWho != null && r.resultWho.equals(resultWho))) {
-                    finishActivityLocked(r, i,
-                            Activity.RESULT_CANCELED, null, "request-sub", false);
+                    finishActivityLocked(r, Activity.RESULT_CANCELED,
+                            null, "request-sub", false);
                 }
             }
         }
@@ -3883,8 +4278,8 @@
             Slog.w(TAG, "  Force finishing activity "
                     + r.intent.getComponent().flattenToShortString());
             int index = mHistory.indexOf(r);
-            r.stack.finishActivityLocked(r, index,
-                    Activity.RESULT_CANCELED, null, "crashed", false);
+            r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                    null, "crashed", false);
             // Also terminate any activities below it that aren't yet
             // stopped, to avoid a situation where one will get
             // re-start our crashing activity once it gets resumed again.
@@ -3897,8 +4292,8 @@
                     if (!r.isHomeActivity || mService.mHomeProcess != r.app) {
                         Slog.w(TAG, "  Force finishing activity "
                                 + r.intent.getComponent().flattenToShortString());
-                        r.stack.finishActivityLocked(r, index,
-                                Activity.RESULT_CANCELED, null, "crashed", false);
+                        r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                                null, "crashed", false);
                     }
                 }
             }
@@ -3925,8 +4320,8 @@
             if (cur.taskAffinity != null && !cur.taskAffinity.equals(r.taskAffinity)) {
                 break;
             }
-            finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null,
-                    "request-affinity", true);
+            finishActivityLocked(cur, Activity.RESULT_CANCELED, null, "request-affinity",
+                    true);
             index--;
         }
         return true;
@@ -3963,30 +4358,17 @@
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
-    final boolean finishActivityLocked(ActivityRecord r,
-            int resultCode, Intent resultData, String reason, boolean oomAdj) {
-        int index = mHistory.indexOf(r);
-        if (index >= 0) {
-            return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
-        }
-        return false;
+    final boolean finishActivityLocked(ActivityRecord r, int resultCode,
+            Intent resultData, String reason, boolean oomAdj) {
+        return finishActivityLocked(r, resultCode, resultData, reason, false, oomAdj);
     }
 
     /**
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
-    final boolean finishActivityLocked(ActivityRecord r, int index,
-            int resultCode, Intent resultData, String reason, boolean oomAdj) {
-        return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
-    }
-
-    /**
-     * @return Returns true if this activity has been removed from the history
-     * list, or false if it is still in the list and will be removed later.
-     */
-    final boolean finishActivityLocked(ActivityRecord r, int index, int resultCode,
-            Intent resultData, String reason, boolean immediate, boolean oomAdj) {
+    final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
+            String reason, boolean immediate, boolean oomAdj) {
         if (r.finishing) {
             Slog.w(TAG, "Duplicate finish request for " + r);
             return false;
@@ -3996,19 +4378,19 @@
         EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                 r.userId, System.identityHashCode(r),
                 r.task.taskId, r.shortComponentName, reason);
-        if (index < (mHistory.size()-1)) {
-            ActivityRecord next = mHistory.get(index+1);
-            if (next.task == r.task) {
-                if (r.frontOfTask) {
-                    // The next activity is now the front of the task.
-                    next.frontOfTask = true;
-                }
-                if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-                    // If the caller asked that this activity (and all above it)
-                    // be cleared when the task is reset, don't lose that information,
-                    // but propagate it up to the next activity.
-                    next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-                }
+        final ArrayList<ActivityRecord> activities = r.task.mActivities;
+        final int index = activities.indexOf(r);
+        if (index < (activities.size() - 1)) {
+            ActivityRecord next = activities.get(index+1);
+            if (r.frontOfTask) {
+                // The next activity is now the front of the task.
+                next.frontOfTask = true;
+            }
+            if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+                // If the caller asked that this activity (and all above it)
+                // be cleared when the task is reset, don't lose that information,
+                // but propagate it up to the next activity.
+                next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
             }
         }
 
@@ -4029,8 +4411,7 @@
         }
 
         if (immediate) {
-            return finishCurrentActivityLocked(r, index,
-                    FINISH_IMMEDIATELY, oomAdj) == null;
+            return finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, oomAdj) == null;
         } else if (mResumedActivity == r) {
             boolean endTask = index <= 0
                     || (mHistory.get(index-1)).task != r.task;
@@ -4053,8 +4434,7 @@
             // If the activity is PAUSING, we will complete the finish once
             // it is done pausing; else we can just directly finish it here.
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
-            return finishCurrentActivityLocked(r, index,
-                    FINISH_AFTER_PAUSE, oomAdj) == null;
+            return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
         }
@@ -4066,18 +4446,9 @@
     private static final int FINISH_AFTER_PAUSE = 1;
     private static final int FINISH_AFTER_VISIBLE = 2;
 
+
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
             int mode, boolean oomAdj) {
-        final int index = mHistory.indexOf(r);
-        if (index < 0) {
-            return null;
-        }
-
-        return finishCurrentActivityLocked(r, index, mode, oomAdj);
-    }
-
-    private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int index, int mode, boolean oomAdj) {
         // First things first: if this activity is currently visible,
         // and the resumed activity is not yet visible, then hold off on
         // finishing until the resumed one becomes visible.
@@ -4294,8 +4665,9 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Removing activity " + r + " from stack");
         }
-        if (r.task != null) {
-            r.task.removeActivity(r);
+        final TaskRecord task = r.task;
+        if (task != null) {
+            task.removeActivity(r);
         }
         mHistory.remove(r);
         r.takeFromHistory();
@@ -4337,31 +4709,34 @@
     final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
         boolean lastIsOpaque = false;
         boolean activityRemoved = false;
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if (r.finishing) {
-                continue;
-            }
-            if (r.fullscreen) {
-                lastIsOpaque = true;
-            }
-            if (owner != null && r.app != owner) {
-                continue;
-            }
-            if (!lastIsOpaque) {
-                continue;
-            }
-            // We can destroy this one if we have its icicle saved and
-            // it is not in the process of pausing/stopping/finishing.
-            if (r.app != null && r != mResumedActivity && r != mPausingActivity
-                    && r.haveState && !r.visible && r.stopped
-                    && r.state != ActivityState.DESTROYING
-                    && r.state != ActivityState.DESTROYED) {
-                if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
-                        + " resumed=" + mResumedActivity
-                        + " pausing=" + mPausingActivity);
-                if (destroyActivityLocked(r, true, oomAdj, reason)) {
-                    activityRemoved = true;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.finishing) {
+                    continue;
+                }
+                if (r.fullscreen) {
+                    lastIsOpaque = true;
+                }
+                if (owner != null && r.app != owner) {
+                    continue;
+                }
+                if (!lastIsOpaque) {
+                    continue;
+                }
+                // We can destroy this one if we have its icicle saved and
+                // it is not in the process of pausing/stopping/finishing.
+                if (r.app != null && r != mResumedActivity && r != mPausingActivity
+                        && r.haveState && !r.visible && r.stopped
+                        && r.state != ActivityState.DESTROYING
+                        && r.state != ActivityState.DESTROYED) {
+                    if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
+                            + " resumed=" + mResumedActivity
+                            + " pausing=" + mPausingActivity);
+                    if (destroyActivityLocked(r, true, oomAdj, reason)) {
+                        activityRemoved = true;
+                    }
                 }
             }
         }
@@ -4481,8 +4856,7 @@
                     mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
                 }
 
-                int index = mHistory.indexOf(r);
-                if (index >= 0) {
+                if (isInStackLocked(token) != null) {
                     if (r.state == ActivityState.DESTROYING) {
                         cleanUpActivityLocked(r, true, false);
                         removeActivityFromHistoryLocked(r);
@@ -4597,6 +4971,7 @@
      * of the stack.
      */
     final void moveHomeToFrontLocked() {
+        newMoveHomeToFrontLocked();
         TaskRecord homeTask = null;
         for (int i=mHistory.size()-1; i>=0; i--) {
             ActivityRecord hr = mHistory.get(i);
@@ -4606,6 +4981,23 @@
             }
         }
         if (homeTask != null) {
+//            moveTaskToFrontLocked(homeTask, null, null);
+        }
+    }
+
+    final void newMoveHomeToFrontLocked() {
+        TaskRecord homeTask = null;
+        for (int taskNdx = mTaskHistory.size() - 1; homeTask == null && taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.isHomeActivity) {
+                    homeTask = r.task;
+                    break;
+                }
+            }
+        }
+        if (homeTask != null) {
             moveTaskToFrontLocked(homeTask, null, null);
         }
     }
@@ -4642,31 +5034,19 @@
     }
 
     final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
-        if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
 
         final int task = tr.taskId;
         int top = mHistory.size()-1;
 
         if (top < 0 || (mHistory.get(top)).task.taskId == task) {
             // nothing to do!
-            if (reason != null &&
-                    (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-                ActivityOptions.abort(options);
-            } else {
-                updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
-            }
             return;
         }
 
-        ArrayList<IBinder> moved = new ArrayList<IBinder>();
-
-        // Applying the affinities may have removed entries from the history,
-        // so get the size again.
-        top = mHistory.size()-1;
-        int pos = top;
 
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
+        int pos = top;
         while (pos >= 0) {
             ActivityRecord r = mHistory.get(pos);
             if (localLOGV) Slog.v(
@@ -4680,18 +5060,37 @@
                 }
                 mHistory.remove(pos);
                 mHistory.add(top, r);
-                moved.add(0, r.appToken);
                 top--;
             }
             pos--;
         }
+        //
+        // Start new code here! Delete everything above.
+        //
+        if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
 
-        if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to front transition: task=" + tr);
+        final int numTasks = mTaskHistory.size();
+        final int index = mTaskHistory.indexOf(tr);
+        if (numTasks == 0 || index < 0 || index == numTasks - 1)  {
+            // nothing to do!
+            if (reason != null &&
+                    (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+                ActivityOptions.abort(options);
+            } else {
+                updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
+            }
+            return;
+        }
+
+        // Shift all activities with this task up to the top
+        // of the stack, keeping them in the same internal order.
+        mTaskHistory.remove(tr);
+        mTaskHistory.add(tr);
+
+        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
         if (reason != null &&
                 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-            mService.mWindowManager.prepareAppTransition(
-                    AppTransition.TRANSIT_NONE, false);
+            mService.mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             ActivityRecord r = topRunningActivityLocked(null);
             if (r != null) {
                 mNoAnimActivities.add(r);
@@ -4702,12 +5101,16 @@
         }
 
         mService.mWindowManager.moveTaskToTop(task);
-        if (VALIDATE_TOKENS) {
-            validateAppTokensLocked();
-        }
 
         finishTaskMoveLocked(task);
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
+
+        if (VALIDATE_TOKENS) {
+            validateAppTokensLocked();
+        }
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
     }
 
     private final void finishTaskMoveLocked(int task) {
@@ -4727,7 +5130,7 @@
      */
     final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
         Slog.i(TAG, "moveTaskToBack: " + task);
-        
+
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
@@ -4750,11 +5153,14 @@
             }
         }
 
-        ArrayList<IBinder> moved = new ArrayList<IBinder>();
-
         if (DEBUG_TRANSITION) Slog.v(TAG,
                 "Prepare to back transition: task=" + task);
-        
+
+        final TaskRecord tr = mTaskIdToTaskRecord.get(task);
+        mTaskHistory.remove(tr);
+        mTaskHistory.add(0, tr);
+
+        // BEGIN REGION TO REMOVE.
         final int N = mHistory.size();
         int bottom = 0;
         int pos = 0;
@@ -4775,16 +5181,18 @@
                 }
                 mHistory.remove(pos);
                 mHistory.add(bottom, r);
-                moved.add(r.appToken);
                 bottom++;
             }
             pos++;
         }
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
+        // END REGION TO REMOVE
 
         if (reason != null &&
                 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
-            mService.mWindowManager.prepareAppTransition(
-                    AppTransition.TRANSIT_NONE, false);
+            mService.mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             ActivityRecord r = topRunningActivityLocked(null);
             if (r != null) {
                 mNoAnimActivities.add(r);
@@ -4794,6 +5202,7 @@
                     AppTransition.TRANSIT_TASK_TO_BACK, false);
         }
         mService.mWindowManager.moveTaskToBottom(task);
+
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
@@ -5108,25 +5517,30 @@
     }
 
     boolean willActivityBeVisibleLocked(IBinder token) {
-        int i;
-        for (i = mHistory.size() - 1; i >= 0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if (r.appToken == token) {
-                    return true;
-            }
-            if (r.fullscreen && !r.finishing) {
-                return false;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.appToken == token) {
+                        return true;
+                }
+                if (r.fullscreen && !r.finishing) {
+                    return false;
+                }
             }
         }
         return true;
     }
 
     void closeSystemDialogsLocked() {
-        for (int i = mHistory.size() - 1; i >= 0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
-                r.stack.finishActivityLocked(r, i,
-                        Activity.RESULT_CANCELED, null, "close-sys", true);
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
+                    r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                            null, "close-sys", true);
+                }
             }
         }
     }
@@ -5159,8 +5573,8 @@
                     r.app = null;
                 }
                 lastTask = r.task;
-                if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                        null, "force-stop", true)) {
+                if (r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null,
+                        "force-stop", true)) {
                     i--;
                 }
             }
@@ -5241,18 +5655,21 @@
             TAG, "Performing unhandledBack(): top activity at " + top);
         if (top > 0) {
             finishActivityLocked(mHistory.get(top),
-                        top, Activity.RESULT_CANCELED, null, "unhandled-back", true);
+                        Activity.RESULT_CANCELED, null, "unhandled-back", true);
         }
     }
 
     void handleAppCrashLocked(ProcessRecord app) {
-        for (int i = mHistory.size() - 1; i >= 0; i--) {
-            ActivityRecord r = mHistory.get(i);
-            if (r.app == app) {
-                Slog.w(TAG, "  Force finishing activity "
-                    + r.intent.getComponent().flattenToShortString());
-                r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                        null, "crashed", false);
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.app == app) {
+                    Slog.w(TAG, "  Force finishing activity "
+                            + r.intent.getComponent().flattenToShortString());
+                    r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed",
+                            false);
+                }
             }
         }
     }
@@ -5307,33 +5724,65 @@
         return starting;
     }
 
-    void verifyActivityRecords() {
-        /* Until we have activity movement implemented for tasks just do the simple test
-        ActivityIterator iterator = new ActivityIterator();
-        int i;
-        int N = mHistory.size();
-        for (i = 0; i < N && iterator.hasNext(); ++i) {
-            ActivityRecord r1 = mHistory.get(i);
-            ActivityRecord r2 = iterator.next();
-            if (r1 != r2) {
+    void rebuildTaskHistory() {
+        mTaskHistory.clear();
+        final int numActivities = mHistory.size();
+        TaskRecord task = null;
+        for (int i = 0; i < numActivities; ++i) {
+            final ActivityRecord r = mHistory.get(i);
+            if (r.task != task) {
+                task = r.task;
+                task.mActivities.clear();
+                mTaskHistory.add(task);
+            }
+            task.mActivities.add(r);
+        }
+    }
+
+    boolean verifyActivityRecords(boolean rebuild) {
+        final int numHistory = mHistory.size();
+        int historyNdx = 0;
+
+        final int numTasks = mTaskHistory.size();
+        int taskNdx;
+        for (taskNdx = historyNdx = 0; taskNdx < numTasks; ++taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final int numActivities = activities.size();
+            int activityNdx;
+            for (activityNdx = 0;
+                    activityNdx < numActivities && historyNdx < numHistory;
+                    ++activityNdx, ++historyNdx) {
+                ActivityRecord r1 = mHistory.get(historyNdx);
+                ActivityRecord r2 = activities.get(activityNdx);
+                if (r1 != r2) {
+                    break;
+                }
+            }
+            if (activityNdx != numActivities) {
+                // either a mismatch or mHistory ran out before mTaskHistory.
                 break;
             }
         }
-        if (i != N || iterator.hasNext()) {
-            Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
-                + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
-        } */
-        // Simple test
-        ActivityIterator iterator = new ActivityIterator();
-        while (iterator.hasNext()) {
-            ActivityRecord r = iterator.next();
-            if (!mHistory.contains(r)) {
-                break;
-            }
+        if (taskNdx != numTasks || historyNdx != numHistory) {
+            logHistories("verifyActivityRecords", rebuild);
+            return true;
         }
-        if (iterator.size() != mHistory.size() || iterator.hasNext()) {
-            Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
-                + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+        return false;
+    }
+
+    private void logHistories(String caller, boolean rebuild) {
+        Slog.w(TAG, "Mismatch! " + caller + "  mHistory=" + mHistory);
+        ArrayList<ArrayList<ActivityRecord>> nestedRecords =
+                new ArrayList<ArrayList<ActivityRecord>>();
+        for (TaskRecord task : mTaskHistory) {
+            nestedRecords.add(task.mActivities);
+        }
+        Slog.w(TAG, "Mismatch! " + caller + " mTaskHistory" + nestedRecords);
+        Slog.w(TAG, "Mismatch! " + caller + " lastHistoryModifier=" + mLastHistoryModifier
+                + " Caller=" + Debug.getCallers(4));
+        if (rebuild) {
+            rebuildTaskHistory();
         }
     }
 
@@ -5353,138 +5802,4 @@
         }
         return task;
     }
-
-    class TaskIterator implements Iterator<TaskRecord> {
-        private int mCur;
-        private boolean mReverse;
-
-        TaskIterator() {
-            this(FORWARD_ITERATOR);
-        }
-
-        TaskIterator(boolean reverse) {
-            reset(reverse);
-        }
-
-        public void reset(boolean reverse) {
-            mReverse = reverse;
-            mCur = reverse ? mTaskHistory.size() - 1 : 0;
-        }
-
-        @Override
-        public boolean hasNext() {
-            if (mReverse) {
-                return mCur >= 0;
-            }
-            return mCur < mTaskHistory.size();
-        }
-
-        @Override
-        public TaskRecord next() {
-            if (hasNext()) {
-                TaskRecord task = mTaskHistory.get(mCur);
-                mCur += (mReverse ? -1 : 1);
-                return task;
-            }
-            throw new NoSuchElementException();
-        }
-
-        @Override
-        public void remove() {
-            throw new IllegalArgumentException();
-        }
-    }
-
-    class ActivityIterator implements Iterator<ActivityRecord> {
-        final TaskIterator mIterator;
-        boolean mReverse;
-        int mCur;
-        TaskRecord mTaskRecord;
-        final boolean mSkipFinishing;
-
-        public ActivityIterator() {
-            this(FORWARD_ITERATOR);
-        }
-
-        public ActivityIterator(boolean reverse) {
-            this(reverse, false);
-        }
-
-        public ActivityIterator(boolean reverse, boolean skipFinishing) {
-            mSkipFinishing = skipFinishing;
-            mIterator = new TaskIterator();
-            reset(reverse);
-        }
-
-        public void reset(boolean reverse) {
-            mReverse = reverse;
-            mIterator.reset(reverse);
-            getNextTaskRecord();
-        }
-
-        private void getNextTaskRecord() {
-            if (mIterator.hasNext()) {
-                mTaskRecord = mIterator.next();
-                mCur = mReverse ? mTaskRecord.mActivities.size() - 1 : 0;
-            }
-        }
-
-        @Override
-        public boolean hasNext() {
-            if (mTaskRecord == null) {
-                return false;
-            }
-            if (mReverse) {
-                return mCur >= 0;
-            }
-            return mCur < mTaskRecord.mActivities.size();
-        }
-
-        @Override
-        public ActivityRecord next() {
-            while (hasNext()) {
-                ActivityRecord r = mTaskRecord.mActivities.get(mCur);
-                mCur += mReverse ? -1 : 1;
-                if (!hasNext()) {
-                    getNextTaskRecord();
-                }
-                if (mSkipFinishing && r.finishing) {
-                    continue;
-                }
-                return r;
-            }
-            throw new NoSuchElementException();
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-        int size() {
-            int size = 0;
-            final TaskIterator iterator = new TaskIterator();
-            while (iterator.hasNext()) {
-                size += iterator.next().mActivities.size();
-            }
-            return size;
-        }
-
-        ActivityRecord peek() {
-            if (mTaskRecord != null && mCur >= 0 && mCur < mTaskRecord.mActivities.size()) {
-                return mTaskRecord.mActivities.get(mCur);
-            }
-            return null;
-        }
-
-        @Override
-        public String toString() {
-            StringBuffer sb = new StringBuffer();
-            for (int i = 0; i < mTaskHistory.size(); ++i) {
-                final TaskRecord task = mTaskHistory.get(i);
-                sb.append("task_").append(i).append("-").append(task.mActivities).append(" ");
-            }
-            return sb.toString();
-        }
-    }
 }
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 347aa7d..f9b0d4c 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -134,7 +134,21 @@
             // Was not previously in list.
             numFullscreen++;
         }
-        mActivities.add(r);
+        // TODO: This only matters to achieve identical results as mHistory. Later we won't need
+        // to skip over finishing activities.
+        int i;
+        for (i = mActivities.size() - 1; i >= 0; --i) {
+            if (!mActivities.get(i).finishing) {
+                break;
+            }
+        }
+        if (i >= 0) {
+            // Add below finishing activities.
+            mActivities.add(i + 1, r);
+        } else {
+            // All activities are finishing, add to top.
+            mActivities.add(r);
+        }
     }
 
     /** @return true if this was the last activity in the task */
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index bb7334a..533db46 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -462,6 +462,7 @@
      * secondary thread to perform connection work, returning quickly.
      */
     public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
+        enforceControlPermission();
         if (!keyStore.isUnlocked()) {
             throw new IllegalStateException("KeyStore isn't unlocked");
         }
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/java/com/android/server/net/LockdownVpnTracker.java
index f32dd09..5b6e485 100644
--- a/services/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/java/com/android/server/net/LockdownVpnTracker.java
@@ -56,7 +56,9 @@
     private static final int MAX_ERROR_COUNT = 4;
 
     private static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
+
     private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
+    private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN";
 
     private final Context mContext;
     private final INetworkManagementService mNetService;
@@ -66,7 +68,8 @@
 
     private final Object mStateLock = new Object();
 
-    private PendingIntent mResetIntent;
+    private final PendingIntent mConfigIntent;
+    private final PendingIntent mResetIntent;
 
     private String mAcceptedEgressIface;
     private String mAcceptedIface;
@@ -86,6 +89,10 @@
         mVpn = Preconditions.checkNotNull(vpn);
         mProfile = Preconditions.checkNotNull(profile);
 
+        final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
+        configIntent.putExtra(EXTRA_PICK_LOCKDOWN, true);
+        mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0);
+
         final Intent resetIntent = new Intent(ACTION_LOCKDOWN_RESET);
         resetIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         mResetIntent = PendingIntent.getBroadcast(mContext, 0, resetIntent, 0);
@@ -193,6 +200,7 @@
             // TODO: support non-standard port numbers
             mNetService.setFirewallEgressDestRule(mProfile.server, 500, true);
             mNetService.setFirewallEgressDestRule(mProfile.server, 4500, true);
+            mNetService.setFirewallEgressDestRule(mProfile.server, 1701, true);
         } catch (RemoteException e) {
             throw new RuntimeException("Problem setting firewall rules", e);
         }
@@ -218,6 +226,7 @@
         try {
             mNetService.setFirewallEgressDestRule(mProfile.server, 500, false);
             mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false);
+            mNetService.setFirewallEgressDestRule(mProfile.server, 1701, false);
         } catch (RemoteException e) {
             throw new RuntimeException("Problem setting firewall rules", e);
         }
@@ -281,10 +290,13 @@
         builder.setWhen(0);
         builder.setSmallIcon(iconRes);
         builder.setContentTitle(mContext.getString(titleRes));
-        builder.setContentText(mContext.getString(R.string.vpn_lockdown_reset));
-        builder.setContentIntent(mResetIntent);
+        builder.setContentText(mContext.getString(R.string.vpn_lockdown_config));
+        builder.setContentIntent(mConfigIntent);
         builder.setPriority(Notification.PRIORITY_LOW);
         builder.setOngoing(true);
+        builder.addAction(
+                R.drawable.ic_menu_refresh, mContext.getString(R.string.reset), mResetIntent);
+
         NotificationManager.from(mContext).notify(TAG, 0, builder.build());
     }
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0c8d9d1..c88ed9c 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1458,7 +1458,7 @@
                 if ("group".equals(name)) {
                     String gidStr = parser.getAttributeValue(null, "gid");
                     if (gidStr != null) {
-                        int gid = Integer.parseInt(gidStr);
+                        int gid = Process.getGidForName(gidStr);
                         mGlobalGids = appendInt(mGlobalGids, gid);
                     } else {
                         Slog.w(TAG, "<group> without gid at "
diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/java/com/android/server/wifi/WifiNotificationController.java
new file mode 100644
index 0000000..17ef7c8
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiNotificationController.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2013 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.wifi;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.TaskStackBuilder;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.NetworkInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiStateMachine;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/* Takes care of handling the "open wi-fi network available" notification @hide */
+final class WifiNotificationController {
+    /**
+     * The icon to show in the 'available networks' notification. This will also
+     * be the ID of the Notification given to the NotificationManager.
+     */
+    private static final int ICON_NETWORKS_AVAILABLE =
+            com.android.internal.R.drawable.stat_notify_wifi_in_range;
+    /**
+     * When a notification is shown, we wait this amount before possibly showing it again.
+     */
+    private final long NOTIFICATION_REPEAT_DELAY_MS;
+    /**
+     * Whether the user has set the setting to show the 'available networks' notification.
+     */
+    private boolean mNotificationEnabled;
+    /**
+     * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
+     */
+    private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
+    /**
+     * The {@link System#currentTimeMillis()} must be at least this value for us
+     * to show the notification again.
+     */
+    private long mNotificationRepeatTime;
+    /**
+     * The Notification object given to the NotificationManager.
+     */
+    private Notification mNotification;
+    /**
+     * Whether the notification is being shown, as set by us. That is, if the
+     * user cancels the notification, we will not receive the callback so this
+     * will still be true. We only guarantee if this is false, then the
+     * notification is not showing.
+     */
+    private boolean mNotificationShown;
+    /**
+     * The number of continuous scans that must occur before consider the
+     * supplicant in a scanning state. This allows supplicant to associate with
+     * remembered networks that are in the scan results.
+     */
+    private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
+    /**
+     * The number of scans since the last network state change. When this
+     * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
+     * supplicant to actually be scanning. When the network state changes to
+     * something other than scanning, we reset this to 0.
+     */
+    private int mNumScansSinceNetworkStateChange;
+
+    private final Context mContext;
+    private final WifiStateMachine mWifiStateMachine;
+    private NetworkInfo mNetworkInfo;
+
+    WifiNotificationController(Context context, WifiStateMachine wsm) {
+        mContext = context;
+        mWifiStateMachine = wsm;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                            resetNotification();
+                        } else if (intent.getAction().equals(
+                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                                    WifiManager.EXTRA_NETWORK_INFO);
+                            // reset & clear notification on a network connect & disconnect
+                            switch(mNetworkInfo.getDetailedState()) {
+                                case CONNECTED:
+                                case DISCONNECTED:
+                                case CAPTIVE_PORTAL_CHECK:
+                                    resetNotification();
+                                    break;
+                            }
+                        } else if (intent.getAction().equals(
+                                WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                            checkAndSetNotification(mNetworkInfo,
+                                    mWifiStateMachine.syncGetScanResultsList());
+                        }
+                    }
+                }, filter);
+
+        // Setting is in seconds
+        NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
+        mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
+        mNotificationEnabledSettingObserver.register();
+    }
+
+    private synchronized void checkAndSetNotification(NetworkInfo networkInfo,
+            List<ScanResult> scanResults) {
+        // TODO: unregister broadcast so we do not have to check here
+        // If we shouldn't place a notification on available networks, then
+        // don't bother doing any of the following
+        if (!mNotificationEnabled) return;
+        if (networkInfo == null) return;
+
+        NetworkInfo.State state = networkInfo.getState();
+        if ((state == NetworkInfo.State.DISCONNECTED)
+                || (state == NetworkInfo.State.UNKNOWN)) {
+            if (scanResults != null) {
+                int numOpenNetworks = 0;
+                for (int i = scanResults.size() - 1; i >= 0; i--) {
+                    ScanResult scanResult = scanResults.get(i);
+
+                    //A capability of [ESS] represents an open access point
+                    //that is available for an STA to connect
+                    if (scanResult.capabilities != null &&
+                            scanResult.capabilities.equals("[ESS]")) {
+                        numOpenNetworks++;
+                    }
+                }
+
+                if (numOpenNetworks > 0) {
+                    if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
+                        /*
+                         * We've scanned continuously at least
+                         * NUM_SCANS_BEFORE_NOTIFICATION times. The user
+                         * probably does not have a remembered network in range,
+                         * since otherwise supplicant would have tried to
+                         * associate and thus resetting this counter.
+                         */
+                        setNotificationVisible(true, numOpenNetworks, false, 0);
+                    }
+                    return;
+                }
+            }
+        }
+
+        // No open networks in range, remove the notification
+        setNotificationVisible(false, 0, false, 0);
+    }
+
+    /**
+     * Clears variables related to tracking whether a notification has been
+     * shown recently and clears the current notification.
+     */
+    private synchronized void resetNotification() {
+        mNotificationRepeatTime = 0;
+        mNumScansSinceNetworkStateChange = 0;
+        setNotificationVisible(false, 0, false, 0);
+    }
+
+    /**
+     * Display or don't display a notification that there are open Wi-Fi networks.
+     * @param visible {@code true} if notification should be visible, {@code false} otherwise
+     * @param numNetworks the number networks seen
+     * @param force {@code true} to force notification to be shown/not-shown,
+     * even if it is already shown/not-shown.
+     * @param delay time in milliseconds after which the notification should be made
+     * visible or invisible.
+     */
+    private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
+            int delay) {
+
+        // Since we use auto cancel on the notification, when the
+        // mNetworksAvailableNotificationShown is true, the notification may
+        // have actually been canceled.  However, when it is false we know
+        // for sure that it is not being shown (it will not be shown any other
+        // place than here)
+
+        // If it should be hidden and it is already hidden, then noop
+        if (!visible && !mNotificationShown && !force) {
+            return;
+        }
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        Message message;
+        if (visible) {
+
+            // Not enough time has passed to show the notification again
+            if (System.currentTimeMillis() < mNotificationRepeatTime) {
+                return;
+            }
+
+            if (mNotification == null) {
+                // Cache the Notification object.
+                mNotification = new Notification();
+                mNotification.when = 0;
+                mNotification.icon = ICON_NETWORKS_AVAILABLE;
+                mNotification.flags = Notification.FLAG_AUTO_CANCEL;
+                mNotification.contentIntent = TaskStackBuilder.create(mContext)
+                        .addNextIntentWithParentStack(
+                                new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
+                        .getPendingIntent(0, 0, null, UserHandle.CURRENT);
+            }
+
+            CharSequence title = mContext.getResources().getQuantityText(
+                    com.android.internal.R.plurals.wifi_available, numNetworks);
+            CharSequence details = mContext.getResources().getQuantityText(
+                    com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
+            mNotification.tickerText = title;
+            mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
+
+            mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
+
+            notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification,
+                    UserHandle.ALL);
+        } else {
+            notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
+        }
+
+        mNotificationShown = visible;
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("mNotificationEnabled " + mNotificationEnabled);
+        pw.println("mNotificationRepeatTime " + mNotificationRepeatTime);
+        pw.println("mNotificationShown " + mNotificationShown);
+        pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange);
+    }
+
+    private class NotificationEnabledSettingObserver extends ContentObserver {
+        public NotificationEnabledSettingObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void register() {
+            ContentResolver cr = mContext.getContentResolver();
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
+            synchronized (WifiNotificationController.this) {
+                mNotificationEnabled = getValue();
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+
+            synchronized (WifiNotificationController.this) {
+                mNotificationEnabled = getValue();
+                resetNotification();
+            }
+        }
+
+        private boolean getValue() {
+            return Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
+        }
+    }
+
+}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
similarity index 70%
rename from services/java/com/android/server/WifiService.java
rename to services/java/com/android/server/wifi/WifiService.java
index ad6eb4d..94b3ed3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -14,45 +14,33 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.wifi;
 
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
-import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.TaskStackBuilder;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.database.ContentObserver;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
-import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiStateMachine;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiWatchdogStateMachine;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WpsInfo;
-import android.net.wifi.WpsResult;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.DhcpResults;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
-import android.net.TrafficStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Messenger;
@@ -61,12 +49,10 @@
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 
@@ -75,11 +61,7 @@
 import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.TelephonyIntents;
@@ -97,13 +79,13 @@
 // as a SM to track soft AP/client/adhoc bring up based
 // on device idle state, airplane mode and boot.
 
-public class WifiService extends IWifiManager.Stub {
+public final class WifiService extends IWifiManager.Stub {
     private static final String TAG = "WifiService";
     private static final boolean DBG = false;
 
     private final WifiStateMachine mWifiStateMachine;
 
-    private Context mContext;
+    private final Context mContext;
 
     private AlarmManager mAlarmManager;
     private PendingIntent mIdleIntent;
@@ -130,19 +112,14 @@
     private final IBatteryStats mBatteryStats;
     private final AppOpsManager mAppOps;
 
-    private boolean mEnableTrafficStatsPoll = false;
-    private int mTrafficStatsPollToken = 0;
-    private long mTxPkts;
-    private long mRxPkts;
-    /* Tracks last reported data activity */
-    private int mDataActivity;
     private String mInterfaceName;
 
-    /**
-     * Interval in milliseconds between polling for traffic
-     * statistics
-     */
-    private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
+    /* Tracks the open wi-fi network notification */
+    private WifiNotificationController mNotificationController;
+    /* Polls traffic stats and notifies clients */
+    private WifiTrafficPoller mTrafficPoller;
+    /* Tracks the persisted states for wi-fi & airplane mode */
+    private WifiSettingsStore mSettingsStore;
 
     /**
      * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
@@ -156,78 +133,14 @@
     private static final String ACTION_DEVICE_IDLE =
             "com.android.server.WifiManager.action.DEVICE_IDLE";
 
-    private static final int WIFI_DISABLED                  = 0;
-    private static final int WIFI_ENABLED                   = 1;
-    /* Wifi enabled while in airplane mode */
-    private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
-    /* Wifi disabled due to airplane mode on */
-    private static final int WIFI_DISABLED_AIRPLANE_ON      = 3;
-
-    /* Persisted state that tracks the wifi & airplane interaction from settings */
-    private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
-    /* Tracks current airplane mode state */
-    private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
-    /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
-    private boolean mWifiEnabled;
-
     /* The work source (UID) that triggered the current WIFI scan, synchronized
      * on this */
     private WorkSource mScanWorkSource;
 
     private boolean mIsReceiverRegistered = false;
 
-
     NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
 
-    // Variables relating to the 'available networks' notification
-    /**
-     * The icon to show in the 'available networks' notification. This will also
-     * be the ID of the Notification given to the NotificationManager.
-     */
-    private static final int ICON_NETWORKS_AVAILABLE =
-            com.android.internal.R.drawable.stat_notify_wifi_in_range;
-    /**
-     * When a notification is shown, we wait this amount before possibly showing it again.
-     */
-    private final long NOTIFICATION_REPEAT_DELAY_MS;
-    /**
-     * Whether the user has set the setting to show the 'available networks' notification.
-     */
-    private boolean mNotificationEnabled;
-    /**
-     * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
-     */
-    private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
-    /**
-     * The {@link System#currentTimeMillis()} must be at least this value for us
-     * to show the notification again.
-     */
-    private long mNotificationRepeatTime;
-    /**
-     * The Notification object given to the NotificationManager.
-     */
-    private Notification mNotification;
-    /**
-     * Whether the notification is being shown, as set by us. That is, if the
-     * user cancels the notification, we will not receive the callback so this
-     * will still be true. We only guarantee if this is false, then the
-     * notification is not showing.
-     */
-    private boolean mNotificationShown;
-    /**
-     * The number of continuous scans that must occur before consider the
-     * supplicant in a scanning state. This allows supplicant to associate with
-     * remembered networks that are in the scan results.
-     */
-    private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
-    /**
-     * The number of scans since the last network state change. When this
-     * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
-     * supplicant to actually be scanning. When the network state changes to
-     * something other than scanning, we reset this to 0.
-     */
-    private int mNumScansSinceNetworkStateChange;
-
     /**
      * Asynchronous channel to WifiStateMachine
      */
@@ -241,9 +154,9 @@
     /**
      * Handles client connections
      */
-    private class AsyncServiceHandler extends Handler {
+    private class ClientHandler extends Handler {
 
-        AsyncServiceHandler(android.os.Looper looper) {
+        ClientHandler(android.os.Looper looper) {
             super(looper);
         }
 
@@ -273,48 +186,13 @@
                     ac.connect(mContext, this, msg.replyTo);
                     break;
                 }
-                case WifiManager.ENABLE_TRAFFIC_STATS_POLL: {
-                    mEnableTrafficStatsPoll = (msg.arg1 == 1);
-                    mTrafficStatsPollToken++;
-                    if (mEnableTrafficStatsPoll) {
-                        notifyOnDataActivity();
-                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
-                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
-                    }
-                    break;
-                }
-                case WifiManager.TRAFFIC_STATS_POLL: {
-                    if (msg.arg1 == mTrafficStatsPollToken) {
-                        notifyOnDataActivity();
-                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
-                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
-                    }
-                    break;
-                }
-                case WifiManager.CONNECT_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.SAVE_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.FORGET_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.START_WPS: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.CANCEL_WPS: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
-                case WifiManager.DISABLE_NETWORK: {
-                    mWifiStateMachine.sendMessage(Message.obtain(msg));
-                    break;
-                }
+                /* Client commands are forwarded to state machine */
+                case WifiManager.CONNECT_NETWORK:
+                case WifiManager.SAVE_NETWORK:
+                case WifiManager.FORGET_NETWORK:
+                case WifiManager.START_WPS:
+                case WifiManager.CANCEL_WPS:
+                case WifiManager.DISABLE_NETWORK:
                 case WifiManager.RSSI_PKTCNT_FETCH: {
                     mWifiStateMachine.sendMessage(Message.obtain(msg));
                     break;
@@ -326,7 +204,7 @@
             }
         }
     }
-    private AsyncServiceHandler mAsyncServiceHandler;
+    private ClientHandler mClientHandler;
 
     /**
      * Handles interaction with WifiStateMachine
@@ -375,7 +253,7 @@
     private final WorkSource mTmpWorkSource = new WorkSource();
     private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
 
-    WifiService(Context context) {
+    public WifiService(Context context) {
         mContext = context;
 
         mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
@@ -389,65 +267,36 @@
         Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
 
+        mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
+        mTrafficPoller = new WifiTrafficPoller(mContext, mClients, mInterfaceName);
+        mSettingsStore = new WifiSettingsStore(mContext);
+
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        mAirplaneModeOn.set(isAirplaneModeOn());
-                        handleAirplaneModeToggled(mAirplaneModeOn.get());
-                        updateWifiState();
+                        if (mSettingsStore.handleAirplaneModeToggled()) {
+                            updateWifiState();
+                        }
                     }
                 },
                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
 
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                                    WifiManager.WIFI_STATE_DISABLED);
-
-                            mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
-
-                           // reset & clear notification on any wifi state change
-                            resetNotification();
-                        } else if (intent.getAction().equals(
-                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
-                                    WifiManager.EXTRA_NETWORK_INFO);
-                            // reset & clear notification on a network connect & disconnect
-                            switch(mNetworkInfo.getDetailedState()) {
-                                case CONNECTED:
-                                case DISCONNECTED:
-                                case CAPTIVE_PORTAL_CHECK:
-                                    evaluateTrafficStatsPolling();
-                                    resetNotification();
-                                    break;
-                            }
-                        } else if (intent.getAction().equals(
+                        if (intent.getAction().equals(
                                 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                             noteScanEnd();
-                            checkAndSetNotification();
                         }
                     }
-                }, filter);
+                }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
 
         HandlerThread wifiThread = new HandlerThread("WifiService");
         wifiThread.start();
-        mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
+        mClientHandler = new ClientHandler(wifiThread.getLooper());
         mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
-
-        // Setting is in seconds
-        NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
-        mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
-        mNotificationEnabledSettingObserver.register();
     }
 
     /** Tell battery stats about a new WIFI scan */
@@ -495,10 +344,8 @@
      * This function is used only at boot time
      */
     public void checkAndStartWifi() {
-        mAirplaneModeOn.set(isAirplaneModeOn());
-        mPersistWifiState.set(getPersistedWifiState());
-        /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
-        boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
+        /* Check if wi-fi needs to be enabled */
+        boolean wifiEnabled = mSettingsStore.shouldWifiBeEnabled();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
 
@@ -511,75 +358,6 @@
 
     }
 
-    private boolean testAndClearWifiSavedState() {
-        final ContentResolver cr = mContext.getContentResolver();
-        int wifiSavedState = 0;
-        try {
-            wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
-            if(wifiSavedState == 1)
-                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
-        } catch (Settings.SettingNotFoundException e) {
-            ;
-        }
-        return (wifiSavedState == 1);
-    }
-
-    private int getPersistedWifiState() {
-        final ContentResolver cr = mContext.getContentResolver();
-        try {
-            return Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
-        } catch (Settings.SettingNotFoundException e) {
-            Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED);
-            return WIFI_DISABLED;
-        }
-    }
-
-    private boolean shouldWifiBeEnabled() {
-        if (mAirplaneModeOn.get()) {
-            return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
-        } else {
-            return mPersistWifiState.get() != WIFI_DISABLED;
-        }
-    }
-
-    private void handleWifiToggled(boolean wifiEnabled) {
-        boolean airplaneEnabled = mAirplaneModeOn.get() && isAirplaneToggleable();
-        if (wifiEnabled) {
-            if (airplaneEnabled) {
-                persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
-            } else {
-                persistWifiState(WIFI_ENABLED);
-            }
-        } else {
-            // When wifi state is disabled, we do not care
-            // if airplane mode is on or not. The scenario of
-            // wifi being disabled due to airplane mode being turned on
-            // is handled handleAirplaneModeToggled()
-            persistWifiState(WIFI_DISABLED);
-        }
-    }
-
-    private void handleAirplaneModeToggled(boolean airplaneEnabled) {
-        if (airplaneEnabled) {
-            // Wifi disabled due to airplane on
-            if (mWifiEnabled) {
-                persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
-            }
-        } else {
-            /* On airplane mode disable, restore wifi state if necessary */
-            if (testAndClearWifiSavedState() ||
-                    mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
-                persistWifiState(WIFI_ENABLED);
-            }
-        }
-    }
-
-    private void persistWifiState(int state) {
-        final ContentResolver cr = mContext.getContentResolver();
-        mPersistWifiState.set(state);
-        Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
-    }
-
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
      * @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -597,9 +375,9 @@
     /**
      * see {@link android.net.wifi.WifiManager#startScan()}
      */
-    public void startScan(boolean forceActive) {
+    public void startScan() {
         enforceChangePermission();
-        mWifiStateMachine.startScan(forceActive);
+        mWifiStateMachine.startScan();
         noteScanStart();
     }
 
@@ -640,24 +418,28 @@
             Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
 
-        if (enable) {
-            reportStartWorkSource();
-        }
-        mWifiStateMachine.setWifiEnabled(enable);
-
         /*
-         * Caller might not have WRITE_SECURE_SETTINGS,
-         * only CHANGE_WIFI_STATE is enforced
-         */
+        * Caller might not have WRITE_SECURE_SETTINGS,
+        * only CHANGE_WIFI_STATE is enforced
+        */
 
         long ident = Binder.clearCallingIdentity();
         try {
-            handleWifiToggled(enable);
+            if (! mSettingsStore.handleWifiToggled(enable)) {
+                // Nothing to do if wifi cannot be toggled
+                return true;
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
 
         if (enable) {
+            reportStartWorkSource();
+        }
+
+        mWifiStateMachine.setWifiEnabled(enable);
+
+        if (enable) {
             if (!mIsReceiverRegistered) {
                 registerForBroadcasts();
                 mIsReceiverRegistered = true;
@@ -1047,7 +829,7 @@
     public Messenger getWifiServiceMessenger() {
         enforceAccessPermission();
         enforceChangePermission();
-        return new Messenger(mAsyncServiceHandler);
+        return new Messenger(mClientHandler);
     }
 
     /** Get a reference to WifiStateMachine handler for AsyncChannel communication */
@@ -1082,14 +864,12 @@
                 }
                 mAlarmManager.cancel(mIdleIntent);
                 mScreenOff = false;
-                evaluateTrafficStatsPolling();
                 setDeviceIdleAndUpdateWifi(false);
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 if (DBG) {
                     Slog.d(TAG, "ACTION_SCREEN_OFF");
                 }
                 mScreenOff = true;
-                evaluateTrafficStatsPolling();
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND the "stay on while plugged in" setting doesn't match the
@@ -1221,11 +1001,11 @@
         }
 
         /* Disable tethering when airplane mode is enabled */
-        if (mAirplaneModeOn.get()) {
+        if (mSettingsStore.isAirplaneModeOn()) {
             mWifiStateMachine.setWifiApEnabled(null, false);
         }
 
-        if (shouldWifiBeEnabled()) {
+        if (mSettingsStore.shouldWifiBeEnabled()) {
             if (wifiShouldBeStarted) {
                 reportStartWorkSource();
                 mWifiStateMachine.setWifiEnabled(true);
@@ -1253,30 +1033,6 @@
         mContext.registerReceiver(mReceiver, intentFilter);
     }
 
-    private boolean isAirplaneSensitive() {
-        String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_RADIOS);
-        return airplaneModeRadios == null
-            || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
-    }
-
-    private boolean isAirplaneToggleable() {
-        String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
-        return toggleableRadios != null
-            && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
-    }
-
-    /**
-     * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
-     * currently on.
-     * @return {@code true} if airplane mode is on.
-     */
-    private boolean isAirplaneModeOn() {
-        return isAirplaneSensitive() && Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -1296,18 +1052,9 @@
         pw.println("mEmergencyCallbackMode " + mEmergencyCallbackMode);
         pw.println("mMulticastEnabled " + mMulticastEnabled);
         pw.println("mMulticastDisabled " + mMulticastDisabled);
-        pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll);
-        pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken);
-        pw.println("mTxPkts " + mTxPkts);
-        pw.println("mRxPkts " + mRxPkts);
-        pw.println("mDataActivity " + mDataActivity);
-        pw.println("mPersistWifiState " + mPersistWifiState.get());
-        pw.println("mAirplaneModeOn " + mAirplaneModeOn.get());
-        pw.println("mWifiEnabled " + mWifiEnabled);
-        pw.println("mNotificationEnabled " + mNotificationEnabled);
-        pw.println("mNotificationRepeatTime " + mNotificationRepeatTime);
-        pw.println("mNotificationShown " + mNotificationShown);
-        pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange);
+        mSettingsStore.dump(fd, pw, args);
+        mNotificationController.dump(fd, pw, args);
+        mTrafficPoller.dump(fd, pw, args);
 
         pw.println("Latest scan results:");
         List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
@@ -1700,194 +1447,4 @@
             return (mMulticasters.size() > 0);
         }
     }
-
-    /**
-     * Evaluate if traffic stats polling is needed based on
-     * connection and screen on status
-     */
-    private void evaluateTrafficStatsPolling() {
-        Message msg;
-        if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
-            msg = Message.obtain(mAsyncServiceHandler,
-                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0);
-        } else {
-            msg = Message.obtain(mAsyncServiceHandler,
-                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0);
-        }
-        msg.sendToTarget();
-    }
-
-    private void notifyOnDataActivity() {
-        long sent, received;
-        long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
-        int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
-
-        mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
-        mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
-
-        if (preTxPkts > 0 || preRxPkts > 0) {
-            sent = mTxPkts - preTxPkts;
-            received = mRxPkts - preRxPkts;
-            if (sent > 0) {
-                dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
-            }
-            if (received > 0) {
-                dataActivity |= WifiManager.DATA_ACTIVITY_IN;
-            }
-
-            if (dataActivity != mDataActivity && !mScreenOff) {
-                mDataActivity = dataActivity;
-                for (AsyncChannel client : mClients) {
-                    client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
-                }
-            }
-        }
-    }
-
-
-    private void checkAndSetNotification() {
-        // If we shouldn't place a notification on available networks, then
-        // don't bother doing any of the following
-        if (!mNotificationEnabled) return;
-
-        State state = mNetworkInfo.getState();
-        if ((state == NetworkInfo.State.DISCONNECTED)
-                || (state == NetworkInfo.State.UNKNOWN)) {
-            // Look for an open network
-            List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
-            if (scanResults != null) {
-                int numOpenNetworks = 0;
-                for (int i = scanResults.size() - 1; i >= 0; i--) {
-                    ScanResult scanResult = scanResults.get(i);
-
-                    //A capability of [ESS] represents an open access point
-                    //that is available for an STA to connect
-                    if (scanResult.capabilities != null &&
-                            scanResult.capabilities.equals("[ESS]")) {
-                        numOpenNetworks++;
-                    }
-                }
-
-                if (numOpenNetworks > 0) {
-                    if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
-                        /*
-                         * We've scanned continuously at least
-                         * NUM_SCANS_BEFORE_NOTIFICATION times. The user
-                         * probably does not have a remembered network in range,
-                         * since otherwise supplicant would have tried to
-                         * associate and thus resetting this counter.
-                         */
-                        setNotificationVisible(true, numOpenNetworks, false, 0);
-                    }
-                    return;
-                }
-            }
-        }
-
-        // No open networks in range, remove the notification
-        setNotificationVisible(false, 0, false, 0);
-    }
-
-    /**
-     * Clears variables related to tracking whether a notification has been
-     * shown recently and clears the current notification.
-     */
-    private void resetNotification() {
-        mNotificationRepeatTime = 0;
-        mNumScansSinceNetworkStateChange = 0;
-        setNotificationVisible(false, 0, false, 0);
-    }
-
-    /**
-     * Display or don't display a notification that there are open Wi-Fi networks.
-     * @param visible {@code true} if notification should be visible, {@code false} otherwise
-     * @param numNetworks the number networks seen
-     * @param force {@code true} to force notification to be shown/not-shown,
-     * even if it is already shown/not-shown.
-     * @param delay time in milliseconds after which the notification should be made
-     * visible or invisible.
-     */
-    private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
-            int delay) {
-
-        // Since we use auto cancel on the notification, when the
-        // mNetworksAvailableNotificationShown is true, the notification may
-        // have actually been canceled.  However, when it is false we know
-        // for sure that it is not being shown (it will not be shown any other
-        // place than here)
-
-        // If it should be hidden and it is already hidden, then noop
-        if (!visible && !mNotificationShown && !force) {
-            return;
-        }
-
-        NotificationManager notificationManager = (NotificationManager) mContext
-                .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        Message message;
-        if (visible) {
-
-            // Not enough time has passed to show the notification again
-            if (System.currentTimeMillis() < mNotificationRepeatTime) {
-                return;
-            }
-
-            if (mNotification == null) {
-                // Cache the Notification object.
-                mNotification = new Notification();
-                mNotification.when = 0;
-                mNotification.icon = ICON_NETWORKS_AVAILABLE;
-                mNotification.flags = Notification.FLAG_AUTO_CANCEL;
-                mNotification.contentIntent = TaskStackBuilder.create(mContext)
-                        .addNextIntentWithParentStack(
-                                new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
-                        .getPendingIntent(0, 0, null, UserHandle.CURRENT);
-            }
-
-            CharSequence title = mContext.getResources().getQuantityText(
-                    com.android.internal.R.plurals.wifi_available, numNetworks);
-            CharSequence details = mContext.getResources().getQuantityText(
-                    com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
-            mNotification.tickerText = title;
-            mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
-
-            mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
-
-            notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification,
-                    UserHandle.ALL);
-        } else {
-            notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
-        }
-
-        mNotificationShown = visible;
-    }
-
-    private class NotificationEnabledSettingObserver extends ContentObserver {
-
-        public NotificationEnabledSettingObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void register() {
-            ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
-            mNotificationEnabled = getValue();
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-
-            mNotificationEnabled = getValue();
-            resetNotification();
-        }
-
-        private boolean getValue() {
-            return Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
-        }
-    }
-
-
 }
diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/java/com/android/server/wifi/WifiSettingsStore.java
new file mode 100644
index 0000000..d7c8752
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiSettingsStore.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2013 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.wifi;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/* Tracks persisted settings for Wi-Fi and airplane mode interaction */
+final class WifiSettingsStore {
+    /* Values tracked in Settings.Global.WIFI_ON */
+    private static final int WIFI_DISABLED                      = 0;
+    private static final int WIFI_ENABLED                       = 1;
+    /* Wifi enabled while in airplane mode */
+    private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE     = 2;
+    /* Wifi disabled due to airplane mode on */
+    private static final int WIFI_DISABLED_AIRPLANE_ON          = 3;
+
+    /* Persisted state that tracks the wifi & airplane interaction from settings */
+    private int mPersistWifiState = WIFI_DISABLED;
+    /* Tracks current airplane mode state */
+    private boolean mAirplaneModeOn = false;
+    /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
+    private final Context mContext;
+
+    /* Tracks if we have checked the saved wi-fi state after boot */
+    private boolean mCheckSavedStateAtBoot = false;
+
+    WifiSettingsStore(Context context) {
+        mContext = context;
+        mAirplaneModeOn = getPersistedAirplaneModeOn();
+        mPersistWifiState = getPersistedWifiState();
+    }
+
+    synchronized boolean shouldWifiBeEnabled() {
+        if (!mCheckSavedStateAtBoot) {
+            mCheckSavedStateAtBoot = true;
+            if (testAndClearWifiSavedState()) return true;
+        }
+
+        if (mAirplaneModeOn) {
+            return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+        } else {
+            return mPersistWifiState != WIFI_DISABLED;
+        }
+    }
+
+    /**
+     * Returns true if airplane mode is currently on.
+     * @return {@code true} if airplane mode is on.
+     */
+    synchronized boolean isAirplaneModeOn() {
+       return mAirplaneModeOn;
+    }
+
+    synchronized boolean handleWifiToggled(boolean wifiEnabled) {
+        // Can Wi-Fi be toggled in airplane mode ?
+        if (mAirplaneModeOn && !isAirplaneToggleable()) {
+            return false;
+        }
+
+        if (wifiEnabled) {
+            if (mAirplaneModeOn) {
+                persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+            } else {
+                persistWifiState(WIFI_ENABLED);
+            }
+        } else {
+            // When wifi state is disabled, we do not care
+            // if airplane mode is on or not. The scenario of
+            // wifi being disabled due to airplane mode being turned on
+            // is handled handleAirplaneModeToggled()
+            persistWifiState(WIFI_DISABLED);
+        }
+        return true;
+    }
+
+    synchronized boolean handleAirplaneModeToggled() {
+        // Is Wi-Fi sensitive to airplane mode changes ?
+        if (!isAirplaneSensitive()) {
+            return false;
+        }
+
+        mAirplaneModeOn = getPersistedAirplaneModeOn();
+        if (mAirplaneModeOn) {
+            // Wifi disabled due to airplane on
+            if (mPersistWifiState == WIFI_ENABLED) {
+                persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
+            }
+        } else {
+            /* On airplane mode disable, restore wifi state if necessary */
+            if (testAndClearWifiSavedState() ||
+                    mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE) {
+                persistWifiState(WIFI_ENABLED);
+            }
+        }
+        return true;
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("mPersistWifiState " + mPersistWifiState);
+        pw.println("mAirplaneModeOn " + mAirplaneModeOn);
+    }
+
+    private void persistWifiState(int state) {
+        final ContentResolver cr = mContext.getContentResolver();
+        mPersistWifiState = state;
+        Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
+    }
+
+    /* Does Wi-Fi need to be disabled when airplane mode is on ? */
+    private boolean isAirplaneSensitive() {
+        String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_RADIOS);
+        return airplaneModeRadios == null
+                || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
+    }
+
+    /* Is Wi-Fi allowed to be re-enabled while airplane mode is on ? */
+    private boolean isAirplaneToggleable() {
+        String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        return toggleableRadios != null
+                && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
+    }
+
+     /* After a reboot, we restore wi-fi to be on if it was turned off temporarily for tethering.
+      * The settings app tracks the saved state, but the framework has to check it at boot to
+      * make sure the wi-fi is turned on in case it was turned off for the purpose of tethering.
+      *
+      * Note that this is not part of the regular WIFI_ON setting because this only needs to
+      * be controlled through the settings app and not the Wi-Fi public API.
+      */
+    private boolean testAndClearWifiSavedState() {
+        final ContentResolver cr = mContext.getContentResolver();
+        int wifiSavedState = 0;
+        try {
+            wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
+            if(wifiSavedState == 1)
+                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
+        } catch (Settings.SettingNotFoundException e) {
+            ;
+        }
+        return (wifiSavedState == 1);
+    }
+
+    private int getPersistedWifiState() {
+        final ContentResolver cr = mContext.getContentResolver();
+        try {
+            return Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
+        } catch (Settings.SettingNotFoundException e) {
+            Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED);
+            return WIFI_DISABLED;
+        }
+    }
+
+    private boolean getPersistedAirplaneModeOn() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+    }
+}
diff --git a/services/java/com/android/server/wifi/WifiTrafficPoller.java b/services/java/com/android/server/wifi/WifiTrafficPoller.java
new file mode 100644
index 0000000..3fcb6c1
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiTrafficPoller.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2013 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.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.NetworkInfo;
+import static android.net.NetworkInfo.DetailedState.CONNECTED;
+import android.net.TrafficStats;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Message;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.android.internal.util.AsyncChannel;
+
+/* Polls for traffic stats and notifies the clients */
+final class WifiTrafficPoller {
+    /**
+     * Interval in milliseconds between polling for traffic
+     * statistics
+     */
+    private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
+
+    private boolean mEnableTrafficStatsPoll = false;
+    private int mTrafficStatsPollToken = 0;
+    private long mTxPkts;
+    private long mRxPkts;
+    /* Tracks last reported data activity */
+    private int mDataActivity;
+
+    private final List<AsyncChannel> mClients;
+    // err on the side of updating at boot since screen on broadcast may be missed
+    // the first time
+    private AtomicBoolean mScreenOn = new AtomicBoolean(true);
+    private final TrafficHandler mTrafficHandler;
+    private NetworkInfo mNetworkInfo;
+    private final String mInterface;
+
+    WifiTrafficPoller(Context context, List<AsyncChannel> clients, String iface) {
+        mClients = clients;
+        mInterface = iface;
+        mTrafficHandler = new TrafficHandler();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(Intent.ACTION_SCREEN_ON);
+
+        context.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (intent.getAction().equals(
+                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                                    WifiManager.EXTRA_NETWORK_INFO);
+                        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+                            mScreenOn.set(false);
+                        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
+                            mScreenOn.set(true);
+                        }
+                        evaluateTrafficStatsPolling();
+                    }
+                }, filter);
+    }
+
+
+    private class TrafficHandler extends Handler {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case WifiManager.ENABLE_TRAFFIC_STATS_POLL: {
+                    mEnableTrafficStatsPoll = (msg.arg1 == 1);
+                    mTrafficStatsPollToken++;
+                    if (mEnableTrafficStatsPoll) {
+                        notifyOnDataActivity();
+                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
+                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
+                    }
+                    break;
+                }
+                case WifiManager.TRAFFIC_STATS_POLL: {
+                    if (msg.arg1 == mTrafficStatsPollToken) {
+                        notifyOnDataActivity();
+                        sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL,
+                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
+                    }
+                    break;
+                }
+            }
+
+        }
+    }
+
+    private void evaluateTrafficStatsPolling() {
+        Message msg;
+        if (mNetworkInfo == null) return;
+        if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) {
+            msg = Message.obtain(mTrafficHandler,
+                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0);
+        } else {
+            msg = Message.obtain(mTrafficHandler,
+                    WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0);
+        }
+        msg.sendToTarget();
+    }
+
+    private void notifyOnDataActivity() {
+        long sent, received;
+        long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
+        int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
+
+        mTxPkts = TrafficStats.getTxPackets(mInterface);
+        mRxPkts = TrafficStats.getRxPackets(mInterface);
+
+        if (preTxPkts > 0 || preRxPkts > 0) {
+            sent = mTxPkts - preTxPkts;
+            received = mRxPkts - preRxPkts;
+            if (sent > 0) {
+                dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
+            }
+            if (received > 0) {
+                dataActivity |= WifiManager.DATA_ACTIVITY_IN;
+            }
+
+            if (dataActivity != mDataActivity && mScreenOn.get()) {
+                mDataActivity = dataActivity;
+                for (AsyncChannel client : mClients) {
+                    client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
+                }
+            }
+        }
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll);
+        pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken);
+        pw.println("mTxPkts " + mTxPkts);
+        pw.println("mRxPkts " + mRxPkts);
+        pw.println("mDataActivity " + mDataActivity);
+    }
+
+}
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 938fa5c..6aae202 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -19,9 +19,6 @@
 import static com.android.server.wm.WindowManagerService.FORWARD_ITERATOR;
 import static com.android.server.wm.WindowManagerService.REVERSE_ITERATOR;
 
-import android.graphics.Rect;
-import android.os.Debug;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -138,7 +135,7 @@
             mTaskIdToTaskList.put(wtoken.groupId, task);
             mTaskLists.add(task);
         } else {
-            task.mAppTokens.add(wtoken);
+            task.mAppTokens.add(addPos, wtoken);
         }
     }
 
@@ -189,55 +186,10 @@
         return mTmpAppIterator;
     }
 
-    class TaskListsIterator implements Iterator<TaskList> {
-        private int mCur;
-        private boolean mReverse;
-
-        TaskListsIterator() {
-            this(false);
-        }
-
-        TaskListsIterator(boolean reverse) {
-            reset(reverse);
-        }
-
-        void reset(boolean reverse) {
-            mReverse = reverse;
-            mCur = reverse ? mTaskLists.size() - 1 : 0;
-        }
-
-        @Override
-        public boolean hasNext() {
-            if (mReverse) {
-                return mCur >= 0;
-            }
-            return mCur < mTaskLists.size();
-        }
-
-        @Override
-        public TaskList next() {
-            if (hasNext()) {
-                TaskList taskList = mTaskLists.get(mCur);
-                mCur += (mReverse ? -1 : 1);
-                return taskList;
-            }
-            throw new NoSuchElementException();
-        }
-
-        @Override
-        public void remove() {
-            throw new IllegalArgumentException();
-        }
-
-        @Override public String toString() {
-            return mTaskLists.toString();
-        }
-    }
-
     class AppTokenIterator implements Iterator<AppWindowToken> {
-        final TaskListsIterator mIterator = new TaskListsIterator();
         boolean mReverse;
-        int mCur;
+        int mTasksNdx;
+        int mActivityNdx;
         TaskList mTaskList;
 
         public AppTokenIterator() {
@@ -250,14 +202,23 @@
 
         void reset(boolean reverse) {
             mReverse = reverse;
-            mIterator.reset(reverse);
+            mTasksNdx = reverse ? mTaskLists.size() - 1 : 0;
             getNextTaskList();
         }
 
         private void getNextTaskList() {
-            if (mIterator.hasNext()) {
-                mTaskList = mIterator.next();
-                mCur = mReverse ? mTaskList.mAppTokens.size() - 1 : 0;
+            if (mReverse) {
+                if (mTasksNdx >= 0) {
+                    mTaskList = mTaskLists.get(mTasksNdx);
+                    --mTasksNdx;
+                    mActivityNdx = mTaskList.mAppTokens.size() - 1;
+                }
+            } else {
+                if (mTasksNdx < mTaskLists.size()) {
+                    mTaskList = mTaskLists.get(mTasksNdx);
+                    ++mTasksNdx;
+                    mActivityNdx = 0;
+                }
             }
         }
 
@@ -267,16 +228,16 @@
                 return false;
             }
             if (mReverse) {
-                return mCur >= 0;
+                return mActivityNdx >= 0;
             }
-            return mCur < mTaskList.mAppTokens.size();
+            return mActivityNdx < mTaskList.mAppTokens.size();
         }
 
         @Override
         public AppWindowToken next() {
             if (hasNext()) {
-                AppWindowToken wtoken = mTaskList.mAppTokens.get(mCur);
-                mCur += mReverse ? -1 : 1;
+                AppWindowToken wtoken = mTaskList.mAppTokens.get(mActivityNdx);
+                mActivityNdx += mReverse ? -1 : 1;
                 if (!hasNext()) {
                     getNextTaskList();
                 }
@@ -292,15 +253,14 @@
 
         int size() {
             int size = 0;
-            final TaskListsIterator iterator = new TaskListsIterator();
-            while (iterator.hasNext()) {
-                size += iterator.next().mAppTokens.size();
+            for (int i = mTaskLists.size() - 1; i >= 0; --i) {
+                size += mTaskLists.get(i).mAppTokens.size();
             }
             return size;
         }
 
         @Override public String toString() {
-            return mIterator.toString();
+            return mTaskLists.toString();
         }
     }
 
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 5d4ab56..ae110dd 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -49,7 +49,6 @@
     BlackFrame mExitingBlackFrame;
     BlackFrame mEnteringBlackFrame;
     int mWidth, mHeight;
-    int mExitAnimId, mEnterAnimId;
 
     int mOriginalRotation;
     int mOriginalWidth, mOriginalHeight;
@@ -190,12 +189,9 @@
     }
 
     public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
-            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation,
-            int exitAnim, int enterAnim) {
+            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
         mContext = context;
         mDisplay = display;
-        mExitAnimId = exitAnim;
-        mEnterAnimId = enterAnim;
 
         // Screenshot does NOT include rotation!
         if (originalRotation == Surface.ROTATION_90
@@ -321,7 +317,7 @@
         setRotationInTransaction(rotation);
         if (TWO_PHASE_ANIMATION) {
             return startAnimation(session, maxAnimationDuration, animationScale,
-                    finalWidth, finalHeight, false);
+                    finalWidth, finalHeight, false, 0, 0);
         }
 
         // Don't start animation yet.
@@ -332,7 +328,8 @@
      * Returns true if animating.
      */
     private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
-            float animationScale, int finalWidth, int finalHeight, boolean dismissing) {
+            float animationScale, int finalWidth, int finalHeight, boolean dismissing,
+            int exitAnim, int enterAnim) {
         if (mSurfaceControl == null) {
             // Can't do animation.
             return false;
@@ -375,10 +372,10 @@
                 + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);
 
         final boolean customAnim;
-        if (mExitAnimId != 0 && mEnterAnimId != 0) {
+        if (exitAnim != 0 && enterAnim != 0) {
             customAnim = true;
-            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, mExitAnimId);
-            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, mEnterAnimId);
+            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
+            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
         } else {
             customAnim = false;
             switch (delta) {
@@ -578,7 +575,7 @@
      * Returns true if animating.
      */
     public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
-            float animationScale, int finalWidth, int finalHeight) {
+            float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
         if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
         if (mSurfaceControl == null) {
             // Can't do animation.
@@ -586,7 +583,7 @@
         }
         if (!mStarted) {
             startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
-                    true);
+                    true, exitAnim, enterAnim);
         }
         if (!mStarted) {
             return false;
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index e82068c..3611f3e 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -182,13 +182,13 @@
 
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags,
-            int flags, Rect outFrame, Rect outContentInsets,
+            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
             Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
         if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
-                outFrame, outContentInsets, outVisibleInsets,
+                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                 outConfig, outSurface);
         if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b193430..086da37 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -544,6 +544,9 @@
 
     DragState mDragState = null;
 
+    // For frozen screen animations.
+    int mExitAnimId, mEnterAnimId;
+
     /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
      * methods. */
     class LayoutFields {
@@ -2637,7 +2640,7 @@
     public int relayoutWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
-            Rect outFrame, Rect outContentInsets,
+            Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
             Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
         boolean toBeDisplayed = false;
         boolean inTouchMode;
@@ -2904,6 +2907,7 @@
                 win.mAppToken.updateReportedVisibilityLocked();
             }
             outFrame.set(win.mCompatFrame);
+            outOverscanInsets.set(win.mOverscanInsets);
             outContentInsets.set(win.mContentInsets);
             outVisibleInsets.set(win.mVisibleInsets);
             if (localLOGV) Slog.v(
@@ -3139,6 +3143,10 @@
                 }
 
                 while (v >= 0) {
+                    if (!iterator.hasNext()) {
+                        mismatch = true;
+                        break;
+                    }
                     AppWindowToken atoken = iterator.next();
                     if (atoken.removed) {
                         continue;
@@ -3152,8 +3160,9 @@
             }
 
             if (mismatch || iterator.hasNext()) {
-                Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks
-                        + " WindowManager=" + iterator);
+                Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks);
+                Slog.w(TAG, "validateAppTokens: Mismatch! WindowManager=" + iterator);
+                Slog.w(TAG, "validateAppTokens: Mismatch! Callers=" + Debug.getCallers(4));
             }
         }
     }
@@ -3332,12 +3341,17 @@
         }
 
         synchronized(mWindowMap) {
-            AppWindowToken atoken = findAppWindowToken(token);
+            final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
                 return;
             }
-            mTaskIdToDisplayContents.get(atoken.groupId).setAppTaskId(atoken, groupId);
+            DisplayContent displayContent = mTaskIdToDisplayContents.get(atoken.groupId);
+            if (displayContent == null) {
+                Slog.w(TAG, "setAppGroupId: No DisplayContent for taskId=" + atoken.groupId);
+                displayContent = getDefaultDisplayContentLocked();
+            }
+            displayContent.setAppTaskId(atoken, groupId);
         }
     }
 
@@ -3496,7 +3510,13 @@
                 if (currentConfig.diff(mTempConfiguration) != 0) {
                     mWaitingForConfig = true;
                     getDefaultDisplayContentLocked().layoutNeeded = true;
-                    startFreezingDisplayLocked(false, 0, 0);
+                    int anim[] = new int[2];
+                    if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
+                        anim[0] = anim[1] = 0;
+                    } else {
+                        mPolicy.selectRotationAnimationLw(anim);
+                    }
+                    startFreezingDisplayLocked(false, anim[0], anim[1]);
                     config = new Configuration(mTempConfiguration);
                 }
             }
@@ -5476,7 +5496,13 @@
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
         getDefaultDisplayContentLocked().layoutNeeded = true;
-        startFreezingDisplayLocked(inTransaction, 0, 0);
+        final int[] anim = new int[2];
+        if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
+            anim[0] = anim[1] = 0;
+        } else {
+            mPolicy.selectRotationAnimationLw(anim);
+        }
+        startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
         // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
         screenRotationAnimation =
                 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
@@ -7281,6 +7307,7 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
+    @Override
     public void setOverscan(int displayId, int left, int top, int right, int bottom) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
@@ -8101,6 +8128,8 @@
     private void updateResizingWindows(final WindowState w) {
         final WindowStateAnimator winAnimator = w.mWinAnimator;
         if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
+            w.mOverscanInsetsChanged |=
+                    !w.mLastOverscanInsets.equals(w.mOverscanInsets);
             w.mContentInsetsChanged |=
                     !w.mLastContentInsets.equals(w.mContentInsets);
             w.mVisibleInsetsChanged |=
@@ -8128,6 +8157,7 @@
                             + " configChanged=" + configChanged);
                 }
 
+                w.mLastOverscanInsets.set(w.mOverscanInsets);
                 w.mLastContentInsets.set(w.mContentInsets);
                 w.mLastVisibleInsets.set(w.mVisibleInsets);
                 makeWindowFreezingScreenIfNeededLocked(w);
@@ -8664,9 +8694,11 @@
                 if (DEBUG_ORIENTATION &&
                         winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
                         TAG, "Resizing " + win + " WITH DRAW PENDING");
-                win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
+                win.mClient.resized(win.mFrame, win.mLastOverscanInsets, win.mLastContentInsets,
+                        win.mLastVisibleInsets,
                         winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
                         configChanged ? win.mConfiguration : null);
+                win.mOverscanInsetsChanged = false;
                 win.mContentInsetsChanged = false;
                 win.mVisibleInsetsChanged = false;
                 winAnimator.mSurfaceResized = false;
@@ -9236,8 +9268,7 @@
         return null;
     }
 
-    private void startFreezingDisplayLocked(boolean inTransaction,
-            int exitAnim, int enterAnim) {
+    private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
         if (mDisplayFrozen) {
             return;
         }
@@ -9269,6 +9300,8 @@
         }
 
         if (CUSTOM_SCREEN_ROTATION) {
+            mExitAnimId = exitAnim;
+            mEnterAnimId = enterAnim;
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
             final int displayId = displayContent.getDisplayId();
             ScreenRotationAnimation screenRotationAnimation =
@@ -9282,8 +9315,7 @@
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             screenRotationAnimation = new ScreenRotationAnimation(mContext,
                     display, mFxSession, inTransaction, displayInfo.logicalWidth,
-                    displayInfo.logicalHeight, display.getRotation(),
-                    exitAnim, enterAnim);
+                    displayInfo.logicalHeight, display.getRotation());
             mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
         }
     }
@@ -9321,9 +9353,14 @@
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
             // TODO(multidisplay): rotation on main screen only.
             DisplayInfo displayInfo = displayContent.getDisplayInfo();
+            // Get rotation animation again, with new top window
+            boolean isDimming = mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY);
+            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
+                mExitAnimId = mEnterAnimId = 0;
+            }
             if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, displayInfo.logicalWidth,
-                        displayInfo.logicalHeight)) {
+                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
                 scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
@@ -9625,6 +9662,18 @@
         }
     }
 
+    void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
+        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
+        if (mDisplayReady) {
+            DisplayContentsIterator dCIterator = new DisplayContentsIterator();
+            while (dCIterator.hasNext()) {
+                dCIterator.next().dump("  ", pw);
+            }
+        } else {
+            pw.println("  NO DISPLAY");
+        }
+    }
+
     void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
         pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
@@ -9746,15 +9795,6 @@
             }
         }
         pw.println();
-        pw.println("  DisplayContents:");
-        if (mDisplayReady) {
-            DisplayContentsIterator dCIterator = new DisplayContentsIterator();
-            while (dCIterator.hasNext()) {
-                dCIterator.next().dump("    ", pw);
-            }
-        } else {
-            pw.println("  NO DISPLAY");
-        }
         pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
         pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
         if (mLastFocus != mCurrentFocus) {
@@ -9934,6 +9974,7 @@
                 pw.println("    p[policy]: policy state");
                 pw.println("    a[animator]: animator state");
                 pw.println("    s[essions]: active sessions");
+                pw.println("    d[isplays]: active display contents");
                 pw.println("    t[okens]: token list");
                 pw.println("    w[indows]: window list");
                 pw.println("  cmd may also be a NAME to dump windows.  NAME may");
@@ -9972,6 +10013,11 @@
                     dumpSessionsLocked(pw, true);
                 }
                 return;
+            } else if ("displays".equals(cmd) || "d".equals(cmd)) {
+                synchronized(mWindowMap) {
+                    dumpDisplayContentsLocked(pw, true);
+                }
+                return;
             } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
                 synchronized(mWindowMap) {
                     dumpTokensLocked(pw, true);
@@ -10022,6 +10068,11 @@
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
             }
+            dumpDisplayContentsLocked(pw, dumpAll);
+            pw.println();
+            if (dumpAll) {
+                pw.println("-------------------------------------------------------------------------------");
+            }
             dumpTokensLocked(pw, dumpAll);
             pw.println();
             if (dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index f0045b1..517c4e4 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -153,6 +153,14 @@
     boolean mContentInsetsChanged;
 
     /**
+     * Insets that determine the area covered by the display overscan region.  These are in the
+     * application's coordinate space (without compatibility scale applied).
+     */
+    final Rect mOverscanInsets = new Rect();
+    final Rect mLastOverscanInsets = new Rect();
+    boolean mOverscanInsetsChanged;
+
+    /**
      * Set to true if we are waiting for this window to receive its
      * given internal insets before laying out other windows based on it.
      */
@@ -206,6 +214,7 @@
 
     final Rect mContainingFrame = new Rect();
     final Rect mDisplayFrame = new Rect();
+    final Rect mOverscanFrame = new Rect();
     final Rect mContentFrame = new Rect();
     final Rect mParentFrame = new Rect();
     final Rect mVisibleFrame = new Rect();
@@ -401,7 +410,7 @@
     }
 
     @Override
-    public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
+    public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
         mHaveFrame = true;
 
         final Rect container = mContainingFrame;
@@ -458,6 +467,9 @@
             mContentChanged = true;
         }
 
+        final Rect overscan = mOverscanFrame;
+        overscan.set(of);
+
         final Rect content = mContentFrame;
         content.set(cf);
 
@@ -489,8 +501,12 @@
         // Now make sure the window fits in the overall display.
         Gravity.applyDisplay(mAttrs.gravity, df, frame);
 
-        // Make sure the system, content and visible frames are inside of the
+        // Make sure the overscan, content and visible frames are inside of the
         // final window frame.
+        if (overscan.left < frame.left) overscan.left = frame.left;
+        if (overscan.top < frame.top) overscan.top = frame.top;
+        if (overscan.right > frame.right) overscan.right = frame.right;
+        if (overscan.bottom > frame.bottom) overscan.bottom = frame.bottom;
         if (content.left < frame.left) content.left = frame.left;
         if (content.top < frame.top) content.top = frame.top;
         if (content.right > frame.right) content.right = frame.right;
@@ -500,6 +516,12 @@
         if (visible.right > frame.right) visible.right = frame.right;
         if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
 
+        final Rect overscanInsets = mOverscanInsets;
+        overscanInsets.left = overscan.left-frame.left;
+        overscanInsets.top = overscan.top-frame.top;
+        overscanInsets.right = frame.right-overscan.right;
+        overscanInsets.bottom = frame.bottom-overscan.bottom;
+
         final Rect contentInsets = mContentInsets;
         contentInsets.left = content.left-frame.left;
         contentInsets.top = content.top-frame.top;
@@ -517,6 +539,7 @@
             // If there is a size compatibility scale being applied to the
             // window, we need to apply this to its insets so that they are
             // reported to the app in its coordinate space.
+            overscanInsets.scale(mInvGlobalScale);
             contentInsets.scale(mInvGlobalScale);
             visibleInsets.scale(mInvGlobalScale);
 
@@ -560,6 +583,11 @@
     }
 
     @Override
+    public Rect getOverscanFrameLw() {
+        return mOverscanFrame;
+    }
+
+    @Override
     public Rect getContentFrameLw() {
         return mContentFrame;
     }
@@ -1259,17 +1287,21 @@
             pw.print(prefix); pw.print("Frames: containing=");
                     mContainingFrame.printShortString(pw);
                     pw.print(" parent="); mParentFrame.printShortString(pw);
-                    pw.print(" display="); mDisplayFrame.printShortString(pw);
+                    pw.println();
+            pw.print(prefix); pw.print("    display="); mDisplayFrame.printShortString(pw);
+                    pw.print(" overscan="); mOverscanFrame.printShortString(pw);
                     pw.println();
             pw.print(prefix); pw.print("    content="); mContentFrame.printShortString(pw);
                     pw.print(" visible="); mVisibleFrame.printShortString(pw);
                     pw.println();
-            pw.print(prefix); pw.print("Cur insets: content=");
-                    mContentInsets.printShortString(pw);
+            pw.print(prefix); pw.print("Cur insets: overscan=");
+                    mOverscanInsets.printShortString(pw);
+                    pw.print(" content="); mContentInsets.printShortString(pw);
                     pw.print(" visible="); mVisibleInsets.printShortString(pw);
                     pw.println();
-            pw.print(prefix); pw.print("Lst insets: content=");
-                    mLastContentInsets.printShortString(pw);
+            pw.print(prefix); pw.print("Lst insets: overscan=");
+                    mLastOverscanInsets.printShortString(pw);
+                    pw.print(" content="); mLastContentInsets.printShortString(pw);
                     pw.print(" visible="); mLastVisibleInsets.printShortString(pw);
                     pw.println();
         }
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index cfc6bd7..29d6e4d 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -551,6 +551,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** {@hide} */
+    @Override
+    public int getUserId() {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public Context createConfigurationContext(Configuration overrideConfiguration) {
         throw new UnsupportedOperationException();
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 0a78908..d2139ea 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -97,7 +97,8 @@
         EXPOSURE ("Exposure"),
         WHITE_BALANCE ("White Balance"),
         COLOR_CUBE ("Color Cube"),
-        COLOR_CUBE_3D_INTRINSIC ("Color Cube (3D LUT intrinsic)");
+        COLOR_CUBE_3D_INTRINSIC ("Color Cube (3D LUT intrinsic)"),
+        USAGE_IO ("Usage io)");
 
 
         private final String name;
@@ -352,6 +353,9 @@
         case COLOR_CUBE_3D_INTRINSIC:
             mTest = new ColorCube(true);
             break;
+        case USAGE_IO:
+            mTest = new UsageIO();
+            break;
         }
 
         mTest.createBaseTest(this, mBitmapIn, mBitmapIn2, mBitmapOut);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/UsageIO.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/UsageIO.java
new file mode 100644
index 0000000..3f86311
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/UsageIO.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 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.rs.image;
+
+import java.lang.Math;
+
+import android.view.Surface;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptIntrinsicConvolve3x3;
+import android.renderscript.ScriptIntrinsicColorMatrix;
+import android.renderscript.Type;
+import android.renderscript.Matrix4f;
+import android.renderscript.ScriptGroup;
+import android.util.Log;
+
+public class UsageIO extends TestBase {
+    private ScriptIntrinsicColorMatrix mMatrix;
+
+    private Allocation mScratchPixelsAllocation1;
+    private Allocation mScratchPixelsAllocation2;
+
+    public UsageIO() {
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        mMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
+
+        Matrix4f m = new Matrix4f();
+        m.set(1, 0, 0.2f);
+        m.set(1, 1, 0.9f);
+        m.set(1, 2, 0.2f);
+        mMatrix.setColorMatrix(m);
+
+        Type connect = mInPixelsAllocation.getType();
+
+        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect, Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT);
+        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, connect, Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
+
+        Surface s = mScratchPixelsAllocation2.getSurface();
+        mScratchPixelsAllocation1.setSurface(s);
+    }
+
+    public void runTest() {
+        mScratchPixelsAllocation1.copyFrom(mInPixelsAllocation);
+        mScratchPixelsAllocation1.ioSend();
+        mScratchPixelsAllocation2.ioReceive();
+        mMatrix.forEach(mScratchPixelsAllocation2, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/SurfaceTexture/Android.mk b/tests/RenderScriptTests/SurfaceTexture/Android.mk
deleted file mode 100644
index d5262ee2..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-# TODO: build fails with this set
-# LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := RsSurfaceTextureOpaque
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SurfaceTexture/AndroidManifest.xml b/tests/RenderScriptTests/SurfaceTexture/AndroidManifest.xml
deleted file mode 100644
index 8aaa239..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.sto">
-    <uses-sdk android:minSdkVersion="14" />
-    <uses-permission android:name="android.permission.CAMERA" />
-    <uses-feature android:name="android.hardware.camera" />
-    <uses-feature android:name="android.hardware.camera.autofocus" />
-
-    <application
-        android:label="RsSurfaceTextureOpaque"
-        android:hardwareAccelerated="true"
-        android:icon="@drawable/test_pattern">
-
-        <activity android:name="SurfaceTextureOpaque">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/SurfaceTexture/res/drawable/test_pattern.png b/tests/RenderScriptTests/SurfaceTexture/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/CameraCapture.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/CameraCapture.java
deleted file mode 100644
index afdab41..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/CameraCapture.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2012 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.example.android.rs.sto;
-
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.List;
-
-public class CameraCapture {
-
-    public interface CameraFrameListener {
-        public void onNewCameraFrame();
-    }
-
-    static final int FRAMES_PER_SEC = 30;
-
-    private Camera mCamera;
-    private SurfaceTexture mSurfaceTexture;
-
-    private int mProgram;
-
-    private int mCameraTransformHandle;
-    private int mTexSamplerHandle;
-    private int mTexCoordHandle;
-    private int mPosCoordHandle;
-
-    private float[] mCameraTransform = new float[16];
-
-    private int mCameraId = 0;
-    private int mWidth;
-    private int mHeight;
-
-    private long mStartCaptureTime = 0;
-
-    private boolean mNewFrameAvailable = false;
-    private boolean mIsOpen = false;
-
-    private CameraFrameListener mListener;
-
-    public synchronized void beginCapture(int cameraId, int width, int height,
-                                          SurfaceTexture st) {
-        mCameraId = cameraId;
-        mSurfaceTexture = st;
-
-        // Open the camera
-        openCamera(width, height);
-
-        // Start the camera
-        mStartCaptureTime = SystemClock.elapsedRealtime();
-        mCamera.startPreview();
-        mIsOpen = true;
-    }
-
-    public void getCurrentFrame() {
-        if (checkNewFrame()) {
-            if (mStartCaptureTime > 0 && SystemClock.elapsedRealtime() - mStartCaptureTime > 2000) {
-                // Lock white-balance and exposure for effects
-                Log.i("CC", "Locking white-balance and exposure!");
-                Camera.Parameters params = mCamera.getParameters();
-                params.setAutoWhiteBalanceLock(true);
-                params.setAutoExposureLock(true);
-                //mCamera.setParameters(params);
-                mStartCaptureTime = 0;
-            }
-
-            mSurfaceTexture.updateTexImage();
-            mSurfaceTexture.getTransformMatrix(mCameraTransform);
-
-            // display it here
-        }
-    }
-
-    public synchronized boolean hasNewFrame() {
-        return mNewFrameAvailable;
-    }
-
-    public synchronized void endCapture() {
-        mIsOpen = false;
-        if (mCamera != null) {
-            mCamera.release();
-            mCamera = null;
-            mSurfaceTexture = null;
-        }
-    }
-
-    public synchronized boolean isOpen() {
-        return mIsOpen;
-    }
-
-    public int getWidth() {
-        return mWidth;
-    }
-
-    public int getHeight() {
-        return mHeight;
-    }
-
-    public void setCameraFrameListener(CameraFrameListener listener) {
-        mListener = listener;
-    }
-
-    private void openCamera(int width, int height) {
-        // Setup camera
-        mCamera = Camera.open(mCameraId);
-        mCamera.setParameters(calcCameraParameters(width, height));
-
-        // Create camera surface texture
-        try {
-            mCamera.setPreviewTexture(mSurfaceTexture);
-        } catch (IOException e) {
-            throw new RuntimeException("Could not bind camera surface texture: " +
-                                       e.getMessage() + "!");
-        }
-
-        // Connect SurfaceTexture to callback
-        mSurfaceTexture.setOnFrameAvailableListener(onCameraFrameAvailableListener);
-    }
-
-    private Camera.Parameters calcCameraParameters(int width, int height) {
-        Camera.Parameters params = mCamera.getParameters();
-        params.setPreviewSize(mWidth, mHeight);
-
-        // Find closest size
-        int closestSize[] = findClosestSize(width, height, params);
-        mWidth = closestSize[0];
-        mHeight = closestSize[1];
-        params.setPreviewSize(mWidth, mHeight);
-
-        // Find closest FPS
-        int closestRange[] = findClosestFpsRange(FRAMES_PER_SEC, params);
-
-        params.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
-                                  closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
-
-        return params;
-    }
-
-    private int[] findClosestSize(int width, int height, Camera.Parameters parameters) {
-        List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
-        int closestWidth = -1;
-        int closestHeight = -1;
-        int smallestWidth = previewSizes.get(0).width;
-        int smallestHeight =  previewSizes.get(0).height;
-        for (Camera.Size size : previewSizes) {
-            // Best match defined as not being larger in either dimension than
-            // the requested size, but as close as possible. The below isn't a
-            // stable selection (reording the size list can give different
-            // results), but since this is a fallback nicety, that's acceptable.
-            if ( size.width <= width &&
-                 size.height <= height &&
-                 size.width >= closestWidth &&
-                 size.height >= closestHeight) {
-                closestWidth = size.width;
-                closestHeight = size.height;
-            }
-            if ( size.width < smallestWidth &&
-                 size.height < smallestHeight) {
-                smallestWidth = size.width;
-                smallestHeight = size.height;
-            }
-        }
-        if (closestWidth == -1) {
-            // Requested size is smaller than any listed size; match with smallest possible
-            closestWidth = smallestWidth;
-            closestHeight = smallestHeight;
-        }
-        int[] closestSize = {closestWidth, closestHeight};
-        return closestSize;
-    }
-
-    private int[] findClosestFpsRange(int fps, Camera.Parameters params) {
-        List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange();
-        int[] closestRange = supportedFpsRanges.get(0);
-        int fpsk = fps * 1000;
-        int minDiff = 1000000;
-        for (int[] range : supportedFpsRanges) {
-            int low = range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
-            int high = range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
-            if (low <= fpsk && high >= fpsk) {
-                int diff = (fpsk - low) + (high - fpsk);
-                if (diff < minDiff) {
-                    closestRange = range;
-                    minDiff = diff;
-                }
-            }
-        }
-        Log.i("CC", "Found closest range: "
-            + closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + " - "
-            + closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
-        return closestRange;
-    }
-
-    private synchronized void signalNewFrame() {
-        mNewFrameAvailable = true;
-        if (mListener != null) {
-            mListener.onNewCameraFrame();
-        }
-    }
-
-    private synchronized boolean checkNewFrame() {
-        if (mNewFrameAvailable) {
-            mNewFrameAvailable = false;
-            return true;
-        }
-        return false;
-    }
-
-    private SurfaceTexture.OnFrameAvailableListener onCameraFrameAvailableListener =
-            new SurfaceTexture.OnFrameAvailableListener() {
-        @Override
-        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
-            signalNewFrame();
-        }
-    };
-}
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaque.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaque.java
deleted file mode 100644
index a51edaa..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaque.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2012 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.example.android.rs.sto;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.View;
-import android.graphics.SurfaceTexture;
-
-import java.lang.Runtime;
-
-public class SurfaceTextureOpaque extends Activity {
-    private SurfaceTextureOpaqueView mView;
-    CameraCapture mCC;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mView = new SurfaceTextureOpaqueView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mView.resume();
-        startCamera();
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mView.pause();
-        mCC.endCapture();
-    }
-
-    cfl mCFL;
-    public void startCamera() {
-        mCC = new CameraCapture();
-        mCFL = new cfl();
-
-        mCC.setCameraFrameListener(mCFL);
-
-        mCC.beginCapture(1, 640, 480, mView.getST());
-    }
-
-    public class cfl implements CameraCapture.CameraFrameListener {
-        public void onNewCameraFrame() {
-            mView.mRender.newFrame();
-        }
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueRS.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueRS.java
deleted file mode 100644
index b638b7d..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueRS.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 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.example.android.rs.sto;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.graphics.SurfaceTexture;
-import android.util.Log;
-
-
-public class SurfaceTextureOpaqueRS {
-    static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2;
-
-    public SurfaceTextureOpaqueRS() {
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private ScriptC_sto mScript;
-    private SurfaceTexture mST;
-    private Allocation mSto;
-    private Allocation mSto2;
-    private Allocation mRto;
-    private ProgramFragment mPF;
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-
-        Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        tb.setX(640);
-        tb.setY(480);
-        mSto = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_GRAPHICS_TEXTURE |
-                                                 Allocation.USAGE_IO_INPUT);
-        mRto = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_GRAPHICS_RENDER_TARGET |
-                                                 Allocation.USAGE_IO_OUTPUT);
-        mSto2 = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_GRAPHICS_TEXTURE |
-                                                 Allocation.USAGE_IO_INPUT);
-        mST = mSto.getSurfaceTexture();
-        mRto.setSurfaceTexture(mSto2.getSurfaceTexture());
-
-        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
-        pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                       ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mPF = pfb.create();
-        mPF.bindSampler(Sampler.CLAMP_NEAREST(mRS), 0);
-        rs.bindProgramFragment(mPF);
-
-        mScript = new ScriptC_sto(mRS, mRes, R.raw.sto);
-        mScript.set_sto(mSto);
-        mScript.set_rto(mRto);
-        mScript.set_sto2(mSto2);
-        mScript.set_pf(mPF);
-
-        mRS.bindRootScript(mScript);
-
-
-        android.util.Log.v("sto", "Init complete");
-    }
-
-    SurfaceTexture getST() {
-        return mST;
-    }
-
-    public void newFrame() {
-        mSto.ioReceive();
-    }
-
-}
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueView.java b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueView.java
deleted file mode 100644
index f5e49f2..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/SurfaceTextureOpaqueView.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 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.example.android.rs.sto;
-
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.SurfaceTexture;
-import android.util.Log;
-
-public class SurfaceTextureOpaqueView extends RSSurfaceView {
-
-    public SurfaceTextureOpaqueView(Context context) {
-        super(context);
-    }
-
-    RenderScriptGL mRS;
-    SurfaceTextureOpaqueRS mRender;
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    SurfaceTexture getST() {
-        RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-        mRS = createRenderScriptGL(sc);
-        mRender = new SurfaceTextureOpaqueRS();
-        mRender.init(mRS, getResources());
-        return mRender.getST();
-    }
-
-}
-
-
diff --git a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/sto.rs b/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/sto.rs
deleted file mode 100644
index efa901a..0000000
--- a/tests/RenderScriptTests/SurfaceTexture/src/com/example/android/rs/sto/sto.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.sto)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-
-rs_program_fragment pf;
-rs_allocation sto;  // camera in
-rs_allocation sto2;
-rs_allocation rto;  // render target
-
-int root() {
-    rsgBindTexture(pf, 0, sto);
-
-#if 1
-    rsgBindColorTarget(rto, 0);
-
-    rsgClearColor(0.f, 1.f, 0.f, 1.f);
-    rsgDrawQuadTexCoords(0, 0, 0, 0,0,
-                         0,500,0, 1,0,
-                         500,500,0, 1, 1,
-                         500, 0, 0, 0, 1 );
-    rsgClearColorTarget(0);
-
-    // io ops
-    rsAllocationIoSend(rto);
-    rsAllocationIoReceive(sto2);
-
-    rsgBindTexture(pf, 0, sto2);
-#endif
-
-    rsgClearColor(0.f, 1.f, 0.f, 1.f);
-    rsgDrawQuadTexCoords(0, 0, 0, 0,0,
-                         0,500,0, 1,0,
-                         500,500,0, 1, 1,
-                         500, 0, 0, 0, 1 );
-
-    return 1;
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 2414d70..8701cc8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -188,11 +188,6 @@
         return delegate.mStyle;
     }
 
-    @LayoutlibDelegate
-    /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
-        // This is for device testing only: pass
-    }
-
     // ---- Private delegate/helper methods ----
 
     private Typeface_Delegate(String family, int style) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 8b643c0..21bef1c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1398,4 +1398,12 @@
         // pass
         return null;
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int getUserId() {
+        return 0; // not used
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index fa660e6..df576d2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public void resized(Rect arg1, Rect arg2, Rect arg3,
+    public void resized(Rect arg1, Rect arg1p5, Rect arg2, Rect arg3,
             boolean arg4, Configuration arg5) throws RemoteException {
         // pass for now.
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 67b0a9c..f7ddbc6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -86,7 +86,7 @@
     }
     @Override
     public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4,
-            int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b,
+            int arg4_5, Rect arg5Z, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b,
             Surface arg8) throws RemoteException {
         // pass for now.
         return 0;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0be453c..bef5824 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -43,7 +43,7 @@
 
     boolean pingSupplicant();
 
-    void startScan(boolean forceActive);
+    void startScan();
 
     List<ScanResult> getScanResults(String callingPackage);
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c08db07..008a81b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -733,26 +733,7 @@
      */
     public boolean startScan() {
         try {
-            mService.startScan(false);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Request a scan for access points. Returns immediately. The availability
-     * of the results is made known later by means of an asynchronous event sent
-     * on completion of the scan.
-     * This is a variant of startScan that forces an active scan, even if passive
-     * scans are the current default
-     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
-     *
-     * @hide
-     */
-    public boolean startScanActive() {
-        try {
-            mService.startScan(true);
+            mService.startScan();
             return true;
         } catch (RemoteException e) {
             return false;
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 7a9f106..59f1889 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -42,11 +42,14 @@
 
     private static final boolean DBG = false;
     private final String mTAG;
-    private static final int DEFAULT_GROUP_OWNER_INTENT = 6;
+    private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
 
-    static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0;
-    static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
-    static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2;
+    static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED     = 0;
+    static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED    = 1;
+    static final int BLUETOOTH_COEXISTENCE_MODE_SENSE       = 2;
+
+    static final int SCAN_WITHOUT_CONNECTION_SETUP          = 1;
+    static final int SCAN_WITH_CONNECTION_SETUP             = 2;
 
     String mInterface = "";
     private boolean mSuspendOptEnabled = false;
@@ -116,15 +119,13 @@
         return (pong != null && pong.equals("PONG"));
     }
 
-    public boolean scan() {
-       return doBooleanCommand("SCAN");
-    }
-
-    public boolean setScanMode(boolean setActive) {
-        if (setActive) {
-            return doBooleanCommand("DRIVER SCAN-ACTIVE");
+    public boolean scan(int type) {
+        if (type == SCAN_WITHOUT_CONNECTION_SETUP) {
+            return doBooleanCommand("SCAN TYPE=ONLY");
+        } else if (type == SCAN_WITH_CONNECTION_SETUP) {
+            return doBooleanCommand("SCAN");
         } else {
-            return doBooleanCommand("DRIVER SCAN-PASSIVE");
+            throw new IllegalArgumentException("Invalid scan type");
         }
     }
 
@@ -332,12 +333,7 @@
     }
 
     public boolean saveConfig() {
-        // Make sure we never write out a value for AP_SCAN other than 1
-        return doBooleanCommand("AP_SCAN 1") && doBooleanCommand("SAVE_CONFIG");
-    }
-
-    public boolean setScanResultHandling(int mode) {
-        return doBooleanCommand("AP_SCAN " + mode);
+        return doBooleanCommand("SAVE_CONFIG");
     }
 
     public boolean addToBlacklist(String bssid) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index ed8b99b..7da4caa 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -139,8 +139,6 @@
     private int mReconnectCount = 0;
     private boolean mIsScanMode = false;
     private boolean mScanResultIsPending = false;
-    /* Tracks if the current scan settings are active */
-    private boolean mSetScanActive = false;
     /* Tracks if state machine has received any screen state change broadcast yet.
      * We can miss one of these at boot.
      */
@@ -305,14 +303,12 @@
     static final int CMD_START_SCAN                       = BASE + 71;
     /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
     static final int CMD_SET_SCAN_MODE                    = BASE + 72;
-    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
-    static final int CMD_SET_SCAN_TYPE                    = BASE + 73;
     /* Disconnect from a network */
-    static final int CMD_DISCONNECT                       = BASE + 74;
+    static final int CMD_DISCONNECT                       = BASE + 73;
     /* Reconnect to a network */
-    static final int CMD_RECONNECT                        = BASE + 75;
+    static final int CMD_RECONNECT                        = BASE + 74;
     /* Reassociate to a network */
-    static final int CMD_REASSOCIATE                      = BASE + 76;
+    static final int CMD_REASSOCIATE                      = BASE + 75;
     /* Controls suspend mode optimizations
      *
      * When high perf mode is enabled, suspend mode optimizations are disabled
@@ -365,9 +361,6 @@
     private static final int CONNECT_MODE   = 1;
     private static final int SCAN_ONLY_MODE = 2;
 
-    private static final int SCAN_ACTIVE = 1;
-    private static final int SCAN_PASSIVE = 2;
-
     private static final int SUCCESS = 1;
     private static final int FAILURE = -1;
 
@@ -632,7 +625,7 @@
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
-                        startScan(false);
+                        startScan();
                     }
                 },
                 new IntentFilter(ACTION_START_SCAN));
@@ -743,9 +736,13 @@
     /**
      * TODO: doc
      */
-    public void startScan(boolean forceActive) {
-        sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
-                SCAN_ACTIVE : SCAN_PASSIVE, 0));
+    public void startScan() {
+        sendMessage(CMD_START_SCAN);
+    }
+
+    private void startScanNative(int type) {
+        mWifiNative.scan(type);
+        mScanResultIsPending = true;
     }
 
     /**
@@ -889,17 +886,6 @@
     /**
      * TODO: doc
      */
-    public void setScanType(boolean active) {
-        if (active) {
-            sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
-        } else {
-            sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
-        }
-    }
-
-    /**
-     * TODO: doc
-     */
     public List<ScanResult> syncGetScanResultsList() {
         synchronized (mScanResultCache) {
             List<ScanResult> scanList = new ArrayList<ScanResult>();
@@ -1931,7 +1917,6 @@
                 case CMD_BLACKLIST_NETWORK:
                 case CMD_CLEAR_BLACKLIST:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_RSSI_POLL:
@@ -2101,7 +2086,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2237,7 +2221,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2365,7 +2348,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2585,7 +2567,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2649,7 +2630,6 @@
                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
                 case WifiMonitor.WPS_OVERLAP_EVENT:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2700,11 +2680,9 @@
             }
 
             if (mIsScanMode) {
-                mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
                 mWifiNative.disconnect();
                 transitionTo(mScanModeState);
             } else {
-                mWifiNative.setScanResultHandling(CONNECT_MODE);
                 mWifiNative.reconnect();
                 // Status pulls in the current supplicant state and network connection state
                 // events over the monitor connection. This helps framework sync up with
@@ -2731,20 +2709,8 @@
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
             switch(message.what) {
-               case CMD_SET_SCAN_TYPE:
-                    mSetScanActive = (message.arg1 == SCAN_ACTIVE);
-                    mWifiNative.setScanMode(mSetScanActive);
-                    break;
                 case CMD_START_SCAN:
-                    boolean forceActive = (message.arg1 == SCAN_ACTIVE);
-                    if (forceActive && !mSetScanActive) {
-                        mWifiNative.setScanMode(forceActive);
-                    }
-                    mWifiNative.scan();
-                    if (forceActive && !mSetScanActive) {
-                        mWifiNative.setScanMode(mSetScanActive);
-                    }
-                    mScanResultIsPending = true;
+                    startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     break;
                 case CMD_SET_COUNTRY_CODE:
                     String country = (String) message.obj;
@@ -2759,7 +2725,7 @@
                     if (mWifiNative.setBand(band)) {
                         mFrequencyBand.set(band);
                         //Fetch the latest scan results when frequency band is set
-                        startScan(true);
+                        startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     } else {
                         loge("Failed to set frequency band " + band);
                     }
@@ -2906,7 +2872,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2942,7 +2907,6 @@
                     /* Queue driver commands */
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3005,12 +2969,14 @@
                         /* Ignore */
                         return HANDLED;
                     } else {
-                        mWifiNative.setScanResultHandling(message.arg1);
                         mWifiNative.reconnect();
                         mIsScanMode = false;
                         transitionTo(mDisconnectedState);
                     }
                     break;
+                case CMD_START_SCAN:
+                    startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
+                    break;
                     /* Ignore */
                 case CMD_DISCONNECT:
                 case CMD_RECONNECT:
@@ -3139,11 +3105,6 @@
                         replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
                     }
                     break;
-                case WifiMonitor.SCAN_RESULTS_EVENT:
-                    /* Set the scan setting back to "connect" mode */
-                    mWifiNative.setScanResultHandling(CONNECT_MODE);
-                    /* Handle scan results */
-                    return NOT_HANDLED;
                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
                     if (DBG) log("Network connection established");
                     mLastNetworkId = message.arg1;
@@ -3216,14 +3177,9 @@
                     }
                     break;
                 case CMD_START_SCAN:
-                    /* When the network is connected, re-scanning can trigger
-                     * a reconnection. Put it in scan-only mode during scan.
-                     * When scan results are received, the mode is switched
-                     * back to CONNECT_MODE.
-                     */
-                    mWifiNative.setScanResultHandling(SCAN_ONLY_MODE);
-                    /* Have the parent state handle the rest */
-                    return NOT_HANDLED;
+                    /* Do not attempt to connect when we are already connected */
+                    startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
+                    break;
                     /* Ignore connection to same network */
                 case WifiManager.CONNECT_NETWORK:
                     int netId = message.arg1;
@@ -3290,16 +3246,6 @@
 
             return HANDLED;
         }
-
-        @Override
-        public void exit() {
-            /* If a scan result is pending in connected state, the supplicant
-             * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
-             */
-            if (mScanResultIsPending) {
-                mWifiNative.setScanResultHandling(CONNECT_MODE);
-            }
-        }
     }
 
     class ObtainingIpState extends State {
@@ -3586,7 +3532,6 @@
                     break;
                 case CMD_SET_SCAN_MODE:
                     if (message.arg1 == SCAN_ONLY_MODE) {
-                        mWifiNative.setScanResultHandling(message.arg1);
                         //Supplicant disconnect to prevent further connects
                         mWifiNative.disconnect();
                         mIsScanMode = true;
@@ -3788,7 +3733,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3896,7 +3840,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3986,7 +3929,6 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING: