Merge "Make sure the correct AnimatorListeners gets called"
diff --git a/api/current.txt b/api/current.txt
index bdab385..d468831 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3431,6 +3431,7 @@
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method protected void onStart();
+    method public void onStateNotSaved();
     method protected void onStop();
     method protected void onTitleChanged(java.lang.CharSequence, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
@@ -30114,7 +30115,6 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
-    method public final void setConnectionService(android.telecom.ConnectionService);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
     method public final void setExtras(android.os.Bundle);
@@ -35102,9 +35102,13 @@
     field public static final int KEYCODE_DEL = 67; // 0x43
     field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
     field public static final int KEYCODE_DPAD_DOWN = 20; // 0x14
+    field public static final int KEYCODE_DPAD_DOWN_LEFT = 269; // 0x10d
+    field public static final int KEYCODE_DPAD_DOWN_RIGHT = 271; // 0x10f
     field public static final int KEYCODE_DPAD_LEFT = 21; // 0x15
     field public static final int KEYCODE_DPAD_RIGHT = 22; // 0x16
     field public static final int KEYCODE_DPAD_UP = 19; // 0x13
+    field public static final int KEYCODE_DPAD_UP_LEFT = 268; // 0x10c
+    field public static final int KEYCODE_DPAD_UP_RIGHT = 270; // 0x10e
     field public static final int KEYCODE_DVR = 173; // 0xad
     field public static final int KEYCODE_E = 33; // 0x21
     field public static final int KEYCODE_EISU = 212; // 0xd4
diff --git a/api/system-current.txt b/api/system-current.txt
index 1025a71..4dd85e6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3535,6 +3535,7 @@
     method public boolean onSearchRequested(android.view.SearchEvent);
     method public boolean onSearchRequested();
     method protected void onStart();
+    method public void onStateNotSaved();
     method protected void onStop();
     method protected void onTitleChanged(java.lang.CharSequence, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
@@ -32316,7 +32317,6 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
-    method public final void setConnectionService(android.telecom.ConnectionService);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
     method public final void setExtras(android.os.Bundle);
@@ -37413,9 +37413,13 @@
     field public static final int KEYCODE_DEL = 67; // 0x43
     field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
     field public static final int KEYCODE_DPAD_DOWN = 20; // 0x14
+    field public static final int KEYCODE_DPAD_DOWN_LEFT = 269; // 0x10d
+    field public static final int KEYCODE_DPAD_DOWN_RIGHT = 271; // 0x10f
     field public static final int KEYCODE_DPAD_LEFT = 21; // 0x15
     field public static final int KEYCODE_DPAD_RIGHT = 22; // 0x16
     field public static final int KEYCODE_DPAD_UP = 19; // 0x13
+    field public static final int KEYCODE_DPAD_UP_LEFT = 268; // 0x10c
+    field public static final int KEYCODE_DPAD_UP_RIGHT = 270; // 0x10e
     field public static final int KEYCODE_DVR = 173; // 0xad
     field public static final int KEYCODE_E = 33; // 0x21
     field public static final int KEYCODE_EISU = 212; // 0xd4
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3ed72e5..85de12f 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -2220,7 +2220,7 @@
     }
 
     private void runSetInactive() throws Exception {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_CURRENT;
 
         String opt;
         while ((opt=nextOption()) != null) {
@@ -2240,7 +2240,7 @@
     }
 
     private void runGetInactive() throws Exception {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_CURRENT;
 
         String opt;
         while ((opt=nextOption()) != null) {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 8b544ab..964b776 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -335,7 +335,7 @@
         boolean listDisabled = false, listEnabled = false;
         boolean listSystem = false, listThirdParty = false;
         boolean listInstaller = false;
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         try {
             String opt;
             while ((opt=nextOption()) != null) {
@@ -846,7 +846,7 @@
 
     // pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
     private int runSetAppLink() {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
 
         String opt;
         while ((opt = nextOption()) != null) {
@@ -929,7 +929,7 @@
 
     // pm get-app-link [--user USER_ID] PACKAGE
     private int runGetAppLink() {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
 
         String opt;
         while ((opt = nextOption()) != null) {
@@ -1090,7 +1090,7 @@
         }
 
         if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_OWNER;
+            userId = UserHandle.USER_SYSTEM;
             installFlags |= PackageManager.INSTALL_ALL_USERS;
         }
 
@@ -1216,7 +1216,7 @@
         }
 
         if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_OWNER;
+            userId = UserHandle.USER_SYSTEM;
             params.installFlags |= PackageManager.INSTALL_ALL_USERS;
         }
 
@@ -1547,7 +1547,7 @@
         }
 
         if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_OWNER;
+            userId = UserHandle.USER_SYSTEM;
             flags |= PackageManager.DELETE_ALL_USERS;
         } else {
             PackageInfo info;
@@ -1758,7 +1758,7 @@
     }
 
     private int runGrantRevokePermission(boolean grant) {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
 
         String opt = null;
         while ((opt = nextOption()) != null) {
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 3e4a66d..9c401c7f 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -138,7 +138,9 @@
                     new AccountAuthenticatorResponse(response),
                         accountType, authTokenType, features, options);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "addAccount: result " + AccountManager.sanitizeResult(result));
                 }
                 if (result != null) {
@@ -160,7 +162,9 @@
                 final Bundle result = AbstractAccountAuthenticator.this.confirmCredentials(
                     new AccountAuthenticatorResponse(response), account, options);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "confirmCredentials: result "
                             + AccountManager.sanitizeResult(result));
                 }
@@ -185,7 +189,9 @@
                 result.putString(AccountManager.KEY_AUTH_TOKEN_LABEL,
                         AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "getAuthTokenLabel: result "
                             + AccountManager.sanitizeResult(result));
                 }
@@ -209,7 +215,9 @@
                         new AccountAuthenticatorResponse(response), account,
                         authTokenType, loginOptions);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "getAuthToken: result " + AccountManager.sanitizeResult(result));
                 }
                 if (result != null) {
@@ -234,7 +242,10 @@
                     new AccountAuthenticatorResponse(response), account,
                         authTokenType, loginOptions);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    // Result may be null.
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "updateCredentials: result "
                             + AccountManager.sanitizeResult(result));
                 }
@@ -490,7 +501,7 @@
      * <ul>
      * <li> {@link AccountManager#KEY_INTENT}, or
      * <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
-     * the account that was added, or
+     * the account whose credentials were updated, or
      * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
      * indicate an error
      * </ul>
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 9394d2c..8c84b4d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -333,7 +333,7 @@
         try {
             return mService.getPassword(account);
         } catch (RemoteException e) {
-            // will never happen
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
@@ -362,7 +362,7 @@
         try {
             return mService.getUserData(account, key);
         } catch (RemoteException e) {
-            // will never happen
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
@@ -415,8 +415,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * @return An array of {@link Account}, one for each account.  Empty
      *     (never null) if no accounts have been added.
@@ -438,8 +440,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * @return An array of {@link Account}, one for each account.  Empty
      *     (never null) if no accounts have been added.
@@ -466,7 +470,7 @@
         try {
             return mService.getAccountsForPackage(packageName, uid);
         } catch (RemoteException re) {
-            // possible security exception
+            // won't ever happen
             throw new RuntimeException(re);
         }
     }
@@ -483,7 +487,7 @@
         try {
             return mService.getAccountsByTypeForPackage(type, packageName);
         } catch (RemoteException re) {
-            // possible security exception
+            // won't ever happen
             throw new RuntimeException(re);
         }
     }
@@ -497,9 +501,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
-     * authenticator that owns the account type.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
      * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
@@ -585,7 +590,8 @@
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
      * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
+     * match with the AbstractAccountAuthenticator that manages the account.
      *
      * @param account The {@link Account} to test
      * @param features An array of the account features to check
@@ -628,9 +634,10 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
-     * authenticator that owns the account type.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * @param type The type of accounts to return, must not be null
      * @param features An array of the account features to require,
@@ -701,7 +708,7 @@
         try {
             return mService.addAccountExplicitly(account, password, userdata);
         } catch (RemoteException e) {
-            // won't ever happen
+            // Can happen if there was a SecurityException was thrown.
             throw new RuntimeException(e);
         }
     }
@@ -966,7 +973,7 @@
         try {
             return mService.removeAccountExplicitly(account);
         } catch (RemoteException e) {
-            // won't ever happen
+            // May happen if the caller doesn't match the signature of the authenticator.
             throw new RuntimeException(e);
         }
     }
@@ -1114,7 +1121,7 @@
         try {
             mService.setUserData(account, key, value);
         } catch (RemoteException e) {
-            // won't ever happen
+            // Will happen if there is not signature match.
             throw new RuntimeException(e);
         }
     }
@@ -1733,7 +1740,7 @@
      *     with these fields if an activity was supplied and the account
      *     credentials were successfully updated:
      * <ul>
-     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
+     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
      * </ul>
      *
@@ -2501,10 +2508,12 @@
      * listeners are added in an Activity or Service's {@link Activity#onCreate}
      * and removed in {@link Activity#onDestroy}.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>The listener will only be informed of accounts that would be returned
+     * to the caller via {@link #getAccounts()}. Typically this means that to
+     * get any accounts, the caller will need to be grated the GET_ACCOUNTS
+     * permission.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * <p>It is safe to call this method from the main thread.
      *
      * @param listener The listener to send notifications to
      * @param handler {@link Handler} identifying the thread to use
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 6db5b9b..f7a7403 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -228,7 +228,9 @@
         int size = mNodes.size();
         for (int i = 0; i < size; i++) {
             Node node = mNodes.get(i);
-            childList.add(node.mAnimation);
+            if (node != mRootNode) {
+                childList.add(node.mAnimation);
+            }
         }
         return childList;
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2f40c18..983af2f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,7 @@
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
+import android.view.Window.WindowStackCallback;
 import android.widget.Toolbar;
 
 import com.android.internal.app.IVoiceInteractor;
@@ -672,7 +673,7 @@
         implements LayoutInflater.Factory2,
         Window.Callback, KeyEvent.Callback,
         OnCreateContextMenuListener, ComponentCallbacks2,
-        Window.OnWindowDismissedCallback {
+        Window.OnWindowDismissedCallback, WindowStackCallback {
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
@@ -683,6 +684,13 @@
     /** Start of user-defined activity results. */
     public static final int RESULT_FIRST_USER   = 1;
 
+    /** @hide Task isn't finished when activity is finished */
+    public static final int DONT_FINISH_TASK_WITH_ACTIVITY = 0;
+    /** @hide Task is finished if the finishing activity is the root of the task */
+    public static final int FINISH_TASK_WITH_ROOT_ACTIVITY = 1;
+    /** @hide Task is finished along with the finishing activity*/
+    public static final int FINISH_TASK_WITH_ACTIVITY = 2;
+
     static final String FRAGMENTS_TAG = "android:fragments";
 
     private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
@@ -1173,6 +1181,16 @@
     }
 
     /**
+     * Called when an {@link #onResume} is coming up, prior to other pre-resume callbacks
+     * such as {@link #onNewIntent} and {@link #onActivityResult}.  This is primarily intended
+     * to give the activity a hint that its state is no longer saved -- it will generally
+     * be called after {@link #onSaveInstanceState} and prior to the activity being
+     * resumed/started again.
+     */
+    public void onStateNotSaved() {
+    }
+
+    /**
      * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or
      * {@link #onPause}, for your activity to start interacting with the user.
      * This is a good place to begin animations, open exclusive-access devices
@@ -2689,8 +2707,30 @@
      * @hide
      */
     @Override
-    public void onWindowDismissed() {
-        finish();
+    public void onWindowDismissed(boolean finishTask) {
+        finish(finishTask ? FINISH_TASK_WITH_ACTIVITY : DONT_FINISH_TASK_WITH_ACTIVITY);
+    }
+
+
+    /** Called to move the window and its activity/task to a different stack container.
+     * For example, a window can move between
+     * {@link android.app.ActivityManager#FULLSCREEN_WORKSPACE_STACK_ID} stack and
+     * {@link android.app.ActivityManager#FREEFORM_WORKSPACE_STACK_ID} stack.
+     *
+     * @param stackId stack Id to change to.
+     * @hide
+     */
+    @Override
+    public void changeWindowStack(int stackId) throws RemoteException {
+        ActivityManagerNative.getDefault().moveActivityToStack(mToken, stackId);
+    }
+
+    /** Returns the current stack Id for the window.
+     * @hide
+     */
+    @Override
+    public int getWindowStackId() throws RemoteException {
+        return ActivityManagerNative.getDefault().getActivityStackId(mToken);
     }
 
     /**
@@ -4838,7 +4878,7 @@
      * Finishes the current activity and specifies whether to remove the task associated with this
      * activity.
      */
-    private void finish(boolean finishTask) {
+    private void finish(int finishTask) {
         if (mParent == null) {
             int resultCode;
             Intent resultData;
@@ -4869,7 +4909,7 @@
      * onActivityResult().
      */
     public void finish() {
-        finish(false);
+        finish(DONT_FINISH_TASK_WITH_ACTIVITY);
     }
 
     /**
@@ -4969,10 +5009,10 @@
 
     /**
      * Call this when your activity is done and should be closed and the task should be completely
-     * removed as a part of finishing the Activity.
+     * removed as a part of finishing the root activity of the task.
      */
     public void finishAndRemoveTask() {
-        finish(true);
+        finish(FINISH_TASK_WITH_ROOT_ACTIVITY);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b7a7d07..78e1b76 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -405,7 +405,7 @@
     public static final int COMPAT_MODE_TOGGLE = 2;
 
     /**
-     * First static stack stack ID.
+     * First static stack ID.
      * @hide
      */
     public static final int FIRST_STATIC_STACK_ID = 0;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e9d4113..4232db4 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -346,7 +346,7 @@
             if (data.readInt() != 0) {
                 resultData = Intent.CREATOR.createFromParcel(data);
             }
-            boolean finishTask = (data.readInt() != 0);
+            int finishTask = data.readInt();
             boolean res = finishActivity(token, resultCode, resultData, finishTask);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
@@ -2636,6 +2636,22 @@
             reply.writeInt(res ? 1 : 0);
             return true;
         }
+        case GET_ACTIVITY_STACK_ID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            int stackId = getActivityStackId(token);
+            reply.writeNoException();
+            reply.writeInt(stackId);
+            return true;
+        }
+        case MOVE_ACTIVITY_TO_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            int stackId = data.readInt();
+            moveActivityToStack(token, stackId);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -2949,7 +2965,7 @@
         data.recycle();
         return result;
     }
-    public boolean finishActivity(IBinder token, int resultCode, Intent resultData, boolean finishTask)
+    public boolean finishActivity(IBinder token, int resultCode, Intent resultData, int finishTask)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2962,7 +2978,7 @@
         } else {
             data.writeInt(0);
         }
-        data.writeInt(finishTask ? 1 : 0);
+        data.writeInt(finishTask);
         mRemote.transact(FINISH_ACTIVITY_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
@@ -6101,5 +6117,32 @@
         return res != 0;
     }
 
+    @Override
+    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        data.writeInt(stackId);
+        mRemote.transact(MOVE_ACTIVITY_TO_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public int getActivityStackId(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(GET_ACTIVITY_STACK_ID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int stackId = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return stackId;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4474c75..594ec41 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2555,7 +2555,8 @@
             // manager to stop us.
             try {
                 ActivityManagerNative.getDefault()
-                    .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
+                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
+                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
             } catch (RemoteException ex) {
                 // Ignore
             }
@@ -3120,6 +3121,7 @@
                 r.activity.mStartedActivity = false;
             }
             try {
+                r.activity.onStateNotSaved();
                 r.activity.mFragments.noteStateNotSaved();
                 if (r.pendingIntents != null) {
                     deliverNewIntents(r, r.pendingIntents);
@@ -3280,7 +3282,8 @@
             // just end this activity.
             try {
                 ActivityManagerNative.getDefault()
-                    .finishActivity(token, Activity.RESULT_CANCELED, null, false);
+                    .finishActivity(token, Activity.RESULT_CANCELED, null,
+                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
             } catch (RemoteException ex) {
             }
         }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index f6e0e1e..6e8e2c4 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -721,29 +721,29 @@
 
     public void onContentChanged() {
     }
-    
+
     public void onWindowFocusChanged(boolean hasFocus) {
     }
 
     public void onAttachedToWindow() {
     }
-    
+
     public void onDetachedFromWindow() {
     }
 
     /** @hide */
     @Override
-    public void onWindowDismissed() {
+    public void onWindowDismissed(boolean finishTask) {
         dismiss();
     }
-    
+
     /**
-     * Called to process key events.  You can override this to intercept all 
-     * key events before they are dispatched to the window.  Be sure to call 
+     * Called to process key events.  You can override this to intercept all
+     * key events before they are dispatched to the window.  Be sure to call
      * this implementation for key events that should be handled normally.
-     * 
+     *
      * @param event The key event.
-     * 
+     *
      * @return boolean Return true if this event was consumed.
      */
     public boolean dispatchKeyEvent(KeyEvent event) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5352465..00e397d 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -93,7 +93,7 @@
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent, Bundle options) throws RemoteException;
     public int startActivityFromRecents(int taskId, Bundle options) throws RemoteException;
-    public boolean finishActivity(IBinder token, int code, Intent data, boolean finishTask)
+    public boolean finishActivity(IBinder token, int code, Intent data, int finishTask)
             throws RemoteException;
     public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
     public boolean finishActivityAffinity(IBinder token) throws RemoteException;
@@ -527,6 +527,9 @@
     // descriptor.
     public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException;
 
+    public int getActivityStackId(IBinder token) throws RemoteException;
+    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -879,4 +882,6 @@
     int START_BINDER_TRACKING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 340;
     int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 341;
     int POSITION_TASK_IN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 342;
+    int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343;
+    int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f21422e..c505b0b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -124,6 +124,12 @@
      *
      * <p> If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
+     *
+     * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a
+     * result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part of
+     * the provisioning flow was successful, although this doesn't guarantee the full flow will
+     * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies
+     * that the user backed-out of provisioning, or some precondition for provisioning wasn't met.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_PROFILE
@@ -158,6 +164,10 @@
      *
      * <p> If provisioning fails, the device is factory reset.
      *
+     * <p>A result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part
+     * of the provisioning flow was successful, although this doesn't guarantee the full flow will
+     * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies
+     * that the user backed-out of provisioning, or some precondition for provisioning wasn't met.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_DEVICE
@@ -165,13 +175,19 @@
 
     /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
-     * allows a mobile device management application which starts managed provisioning to pass data
-     * to itself.
+     * allows a mobile device management application or NFC programmer application which starts
+     * managed provisioning to pass data to the management application instance after provisioning.
      * <p>
      * If used with {@link #ACTION_PROVISION_MANAGED_PROFILE} it can be used by the application that
      * sends the intent to pass data to itself on the newly created profile.
      * If used with {@link #ACTION_PROVISION_MANAGED_DEVICE} it allows passing data to the same
      * instance of the app on the primary user.
+     * Starting from {@link android.os.Build.VERSION_CODES#M}, if used with
+     * {@link #MIME_TYPE_PROVISIONING_NFC} as part of NFC managed device provisioning, the NFC
+     * message should contain a stringified {@link java.util.Properties} instance, whose string
+     * properties will be converted into a {@link android.os.PersistableBundle} and passed to the
+     * management application after provisioning.
+     *
      * <p>
      * In both cases the application receives the data in
      * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action
@@ -587,7 +603,9 @@
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li></ul>
+     * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional, supported from
+     * {@link android.os.Build.VERSION_CODES#M} </li></ul>
      *
      * <p>
      * As of {@link android.os.Build.VERSION_CODES#M}, the properties should contain
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 97afafa..1f3ff51 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1002,6 +1002,25 @@
     }
 
     /**
+     * Factory reset bluetooth settings.
+     *
+     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}
+     * permission
+     *
+     * @return true to indicate that the config file was successfully cleared
+     *
+     * @hide
+     */
+    public boolean factoryReset() {
+        try {
+            if (mService != null) {
+                return mService.factoryReset();
+            }
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
      * Get the UUIDs supported by the local Bluetooth adapter.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 7a894ae..66f3418 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -92,6 +92,7 @@
     ParcelFileDescriptor createSocketChannel(int type, in String serviceName, in ParcelUuid uuid, int port, int flag);
 
     boolean configHciSnoopLog(boolean enable);
+    boolean factoryReset();
 
     boolean isMultiAdvertisementSupported();
     boolean isPeripheralModeSupported();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 16ab50d..537a2e9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3815,6 +3815,9 @@
     public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
             "android.intent.extra.SIM_ACTIVATION_RESPONSE";
 
+    /** {@hide} */
+    public static final String EXTRA_INDEX = "android.intent.extra.INDEX";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 9548d49..2620571 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -16,6 +16,8 @@
 
 package android.content.res;
 
+import android.annotation.NonNull;
+
 import java.util.Objects;
 
 /** @hide */
@@ -25,27 +27,27 @@
     private final int mHash;
 
     public final int mDisplayId;
+    @NonNull
     public final Configuration mOverrideConfiguration;
 
     public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
             float scale) {
         mResDir = resDir;
         mDisplayId = displayId;
-        mOverrideConfiguration = overrideConfiguration;
+        mOverrideConfiguration = overrideConfiguration != null
+                ? overrideConfiguration : Configuration.EMPTY;
         mScale = scale;
 
         int hash = 17;
         hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
         hash = 31 * hash + mDisplayId;
-        hash = 31 * hash + (mOverrideConfiguration != null
-                ? mOverrideConfiguration.hashCode() : 0);
+        hash = 31 * hash + mOverrideConfiguration.hashCode();
         hash = 31 * hash + Float.floatToIntBits(mScale);
         mHash = hash;
     }
 
     public boolean hasOverrideConfiguration() {
-        return mOverrideConfiguration != null
-                && !Configuration.EMPTY.equals(mOverrideConfiguration);
+        return !Configuration.EMPTY.equals(mOverrideConfiguration);
     }
 
     @Override
@@ -66,13 +68,8 @@
         if (mDisplayId != peer.mDisplayId) {
             return false;
         }
-        if (mOverrideConfiguration != peer.mOverrideConfiguration) {
-            if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
-                return false;
-            }
-            if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
-                return false;
-            }
+        if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
+            return false;
         }
         if (mScale != peer.mScale) {
             return false;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 10373cf..f2cbe98 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -964,41 +964,6 @@
         return 1;
     }
 
-    /**
-     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability from the given
-     * NetworkCapabilities object if all the capabilities it provides are
-     * typically provided by restricted networks.
-     *
-     * TODO: consider:
-     * - Moving to NetworkCapabilities
-     * - Renaming it to guessRestrictedCapability and make it set the
-     *   restricted capability bit in addition to clearing it.
-     * @hide
-     */
-    public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) {
-        for (int capability : nc.getCapabilities()) {
-            switch (capability) {
-                case NetworkCapabilities.NET_CAPABILITY_CBS:
-                case NetworkCapabilities.NET_CAPABILITY_DUN:
-                case NetworkCapabilities.NET_CAPABILITY_EIMS:
-                case NetworkCapabilities.NET_CAPABILITY_FOTA:
-                case NetworkCapabilities.NET_CAPABILITY_IA:
-                case NetworkCapabilities.NET_CAPABILITY_IMS:
-                case NetworkCapabilities.NET_CAPABILITY_RCS:
-                case NetworkCapabilities.NET_CAPABILITY_XCAP:
-                case NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED: //there by default
-                    continue;
-                default:
-                    // At least one capability usually provided by unrestricted
-                    // networks. Conclude that this network is unrestricted.
-                    return;
-            }
-        }
-        // All the capabilities are typically provided by restricted networks.
-        // Conclude that this network is restricted.
-        nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
-    }
-
     private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
         if (networkType == TYPE_MOBILE) {
             int cap = -1;
@@ -1021,14 +986,14 @@
             }
             NetworkCapabilities netCap = new NetworkCapabilities();
             netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
-            maybeMarkCapabilitiesRestricted(netCap);
+            netCap.maybeMarkCapabilitiesRestricted();
             return netCap;
         } else if (networkType == TYPE_WIFI) {
             if ("p2p".equals(feature)) {
                 NetworkCapabilities netCap = new NetworkCapabilities();
                 netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
                 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
-                maybeMarkCapabilitiesRestricted(netCap);
+                netCap.maybeMarkCapabilitiesRestricted();
                 return netCap;
             }
         }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index af2068c..a6d477f 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -216,6 +216,20 @@
             (1 << NET_CAPABILITY_NOT_VPN);
 
     /**
+     * Capabilities that suggest that a network is restricted.
+     * {@see #maybeMarkCapabilitiesRestricted}.
+     */
+    private static final long RESTRICTED_CAPABILITIES =
+            (1 << NET_CAPABILITY_CBS) |
+            (1 << NET_CAPABILITY_DUN) |
+            (1 << NET_CAPABILITY_EIMS) |
+            (1 << NET_CAPABILITY_FOTA) |
+            (1 << NET_CAPABILITY_IA) |
+            (1 << NET_CAPABILITY_IMS) |
+            (1 << NET_CAPABILITY_RCS) |
+            (1 << NET_CAPABILITY_XCAP);
+
+    /**
      * Adds the given capability to this {@code NetworkCapability} instance.
      * Multiple capabilities may be applied sequentially.  Note that when searching
      * for a network to satisfy a request, all capabilities requested must be satisfied.
@@ -326,6 +340,22 @@
     }
 
     /**
+     * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
+     * typically provided by restricted networks.
+     *
+     * TODO: consider:
+     * - Renaming it to guessRestrictedCapability and make it set the
+     *   restricted capability bit in addition to clearing it.
+     * @hide
+     */
+    public void maybeMarkCapabilitiesRestricted() {
+        // If all the capabilities are typically provided by restricted networks, conclude that this
+        // network is restricted.
+        if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0)
+            removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+    }
+
+    /**
      * Representing the transport type.  Apps should generally not care about transport.  A
      * request for a fast internet connection could be satisfied by a number of different
      * transports.  If any are specified here it will be satisfied a Network that matches
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 4f570dc..7da4818 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -83,7 +83,13 @@
          * Build {@link NetworkRequest} give the current set of capabilities.
          */
         public NetworkRequest build() {
-            return new NetworkRequest(mNetworkCapabilities, ConnectivityManager.TYPE_NONE,
+            // Make a copy of mNetworkCapabilities so we don't inadvertently remove NOT_RESTRICTED
+            // when later an unrestricted capability could be added to mNetworkCapabilities, in
+            // which case NOT_RESTRICTED should be returned to mNetworkCapabilities, which
+            // maybeMarkCapabilitiesRestricted() doesn't add back.
+            final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
+            nc.maybeMarkCapabilitiesRestricted();
+            return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
                     ConnectivityManager.REQUEST_ID_UNSET);
         }
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 8114155..cd84c8f 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -388,8 +388,10 @@
 
     /**
      * Setup a new physical network.
+     * @param permission null if no permissions required to access this network.  PERMISSION_NETWORK
+     *                   or PERMISSION_SYSTEM to set respective permission.
      */
-    void createPhysicalNetwork(int netId);
+    void createPhysicalNetwork(int netId, String permission);
 
     /**
      * Setup a new VPN.
@@ -416,6 +418,13 @@
     void setDefaultNetId(int netId);
     void clearDefaultNetId();
 
+    /**
+     * Set permission for a network.
+     * @param permission null to clear permissions. PERMISSION_NETWORK or PERMISSION_SYSTEM to set
+     *                   permission.
+     */
+    void setNetworkPermission(int netId, String permission);
+
     void setPermission(String permission, in int[] uids);
     void clearPermission(in int[] uids);
 
diff --git a/core/java/android/os/NullVibrator.java b/core/java/android/os/NullVibrator.java
index f14d965..19b452f 100644
--- a/core/java/android/os/NullVibrator.java
+++ b/core/java/android/os/NullVibrator.java
@@ -43,7 +43,6 @@
      */
     @Override
     public void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) {
-        vibrate(milliseconds);
     }
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 138be87..b7c049a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -595,14 +595,24 @@
     public boolean isSystemUser() {
         return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
     }
+
     /**
      * @hide
      * Returns whether the caller is running as an admin user. There can be more than one admin
      * user.
      */
     public boolean isAdminUser() {
-        UserInfo user = getUserInfo(UserHandle.myUserId());
-        return user != null ? user.isAdmin() : false;
+        return isUserAdmin(UserHandle.myUserId());
+    }
+
+    /**
+     * @hide
+     * Returns whether the provided user is an admin user. There can be more than one admin
+     * user.
+     */
+    public boolean isUserAdmin(int userId) {
+        UserInfo user = getUserInfo(userId);
+        return user != null && user.isAdmin();
     }
 
     /**
@@ -1070,7 +1080,7 @@
      */
     public List<UserHandle> getUserProfiles() {
         ArrayList<UserHandle> profiles = new ArrayList<UserHandle>();
-        List<UserInfo> users = new ArrayList<UserInfo>();
+        List<UserInfo> users;
         try {
             users = mService.getProfiles(UserHandle.myUserId(), true /* enabledOnly */);
         } catch (RemoteException re) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 23555d6..4f880b1 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -421,7 +421,7 @@
                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
                 long start, int duration, Long dataUsage) {
             return addCall(ci, context, number, presentation, callType, features, accountHandle,
-                    start, duration, dataUsage, false);
+                    start, duration, dataUsage, false, false);
         }
 
 
@@ -450,8 +450,41 @@
          * {@hide}
          */
         public static Uri addCall(CallerInfo ci, Context context, String number,
+                                  int presentation, int callType, int features, PhoneAccountHandle accountHandle,
+                                  long start, int duration, Long dataUsage, boolean addForAllUsers) {
+            return addCall(ci, context, number, presentation, callType, features, accountHandle,
+                    start, duration, dataUsage, addForAllUsers, false);
+        }
+
+        /**
+         * Adds a call to the call log.
+         *
+         * @param ci the CallerInfo object to get the target contact from.  Can be null
+         * if the contact is unknown.
+         * @param context the context used to get the ContentResolver
+         * @param number the phone number to be added to the calls db
+         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+         *        is set by the network and denotes the number presenting rules for
+         *        "allowed", "payphone", "restricted" or "unknown"
+         * @param callType enumerated values for "incoming", "outgoing", or "missed"
+         * @param features features of the call (e.g. Video).
+         * @param accountHandle The accountHandle object identifying the provider of the call
+         * @param start time stamp for the call in milliseconds
+         * @param duration call duration in seconds
+         * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
+         *                  the call.
+         * @param addForAllUsers If true, the call is added to the call log of all currently
+         *        running users. The caller must have the MANAGE_USERS permission if this is true.
+         * @param is_read Flag to show if the missed call log has been read by the user or not.
+         *                Used for call log restore of missed calls.
+         *
+         * @result The URI of the call log entry belonging to the user that made or received this
+         *        call.
+         * {@hide}
+         */
+        public static Uri addCall(CallerInfo ci, Context context, String number,
                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
-                long start, int duration, Long dataUsage, boolean addForAllUsers) {
+                long start, int duration, Long dataUsage, boolean addForAllUsers, boolean is_read) {
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
 
@@ -516,7 +549,7 @@
             values.put(NEW, Integer.valueOf(1));
 
             if (callType == MISSED_TYPE) {
-                values.put(IS_READ, Integer.valueOf(0));
+                values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0));
             }
 
             if ((ci != null) && (ci.contactIdOrZero > 0)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f2bf6dc..601403c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7567,6 +7567,13 @@
         }
 
         /**
+         * Value of the ringer before entering zen mode.
+         *
+         * @hide
+         */
+        public static final String ZEN_MODE_RINGER_LEVEL = "zen_mode_ringer_level";
+
+        /**
          * Opaque value, changes when persisted zen mode configuration changes.
          *
          * @hide
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index fa015b2..c3aed75 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -40,6 +40,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.MissingResourceException;
@@ -247,7 +248,7 @@
      * @return A list of features supported for the given language.
      */
     protected Set<String> onGetFeaturesForLanguage(String lang, String country, String variant) {
-        return null;
+        return new HashSet<String>();
     }
 
     private int getExpectedLanguageAvailableStatus(Locale locale) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5994d4f..0a4b982 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -80,10 +80,37 @@
     void setEventDispatching(boolean enabled);
     void addWindowToken(IBinder token, int type);
     void removeWindowToken(IBinder token);
-    void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
+    /**
+     * Adds an application token to the specified task Id.
+     * @param addPos The position to add the token to in the task.
+     * @param token The token to add.
+     * @param taskId The Id of the task we are adding the token to.
+     * @param stackId Stack Id to create a new Task with the input task Id on
+     *                if the task doesn't exist yet.
+     * @param requestedOrientation Orientation to use.
+     * @param fullscreen True if the application token is fullscreen.
+     * @param showWhenLocked True if the application token should be shown when locked.
+     * @param userId Id of user to associate the token with.
+     * @param configChanges Input configuration changes.
+     * @param voiceInteraction True if the token is in voice interaction mode.
+     * @param launchTaskBehind True if the token is been launched from behind.
+     * @param taskBounds Bounds to use when creating a new Task with the input task Id if
+     *                   the task doesn't exist yet.
+     * @return The configuration of the task if it was newly created. null otherwise.
+     */
+    Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
-            int configChanges, boolean voiceInteraction, boolean launchTaskBehind);
-    void setAppTask(IBinder token, int taskId);
+            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
+            in Rect taskBounds);
+    /**
+     *
+     * @param token The token we are adding to the input task Id.
+     * @param taskId The Id of the task we are adding the token to.
+     * @param taskBounds Bounds to use when creating a new Task with the input task Id if
+     *                   the task doesn't exist yet.
+     * @return The configuration of the task if it was newly created. null otherwise.
+     */
+    Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 75e6229..e77daa6 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -770,8 +770,16 @@
     public static final int KEYCODE_STEM_2 = 266;
     /** Key code constant: Generic stem key 3 for Wear */
     public static final int KEYCODE_STEM_3 = 267;
+    /** Key code constant: Directional Pad Up-Left */
+    public static final int KEYCODE_DPAD_UP_LEFT    = 268;
+    /** Key code constant: Directional Pad Down-Left */
+    public static final int KEYCODE_DPAD_DOWN_LEFT  = 269;
+    /** Key code constant: Directional Pad Up-Right */
+    public static final int KEYCODE_DPAD_UP_RIGHT   = 270;
+    /** Key code constant: Directional Pad Down-Right */
+    public static final int KEYCODE_DPAD_DOWN_RIGHT = 271;
 
-    private static final int LAST_KEYCODE = KEYCODE_STEM_3;
+    private static final int LAST_KEYCODE = KEYCODE_DPAD_DOWN_RIGHT;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 07984e9..4fc2ad3 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -34,6 +34,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.transition.Scene;
 import android.transition.Transition;
@@ -471,8 +472,24 @@
         /**
          * Called when a window is dismissed. This informs the callback that the
          * window is gone, and it should finish itself.
+         * @param finishTask True if the task should also be finished.
          */
-        public void onWindowDismissed();
+        void onWindowDismissed(boolean finishTask);
+    }
+
+    /** @hide */
+    public interface WindowStackCallback {
+        /** Called to move the window and its activity/task to a different stack container.
+         * For example, a window can move between
+         * {@link android.app.ActivityManager#FULLSCREEN_WORKSPACE_STACK_ID} stack and
+         * {@link android.app.ActivityManager#FREEFORM_WORKSPACE_STACK_ID} stack.
+         *
+         * @param stackId stack Id to change to.
+         */
+        void changeWindowStack(int stackId) throws RemoteException;
+
+        /** Returns the current stack Id for the window. */
+        int getWindowStackId() throws RemoteException;
     }
 
     public Window(Context context) {
@@ -659,7 +676,7 @@
     /** @hide */
     public final void dispatchOnWindowDismissed() {
         if (mOnWindowDismissedCallback != null) {
-            mOnWindowDismissedCallback.onWindowDismissed();
+            mOnWindowDismissedCallback.onWindowDismissed(false);
         }
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 8364951..20fe61d 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -384,6 +384,10 @@
         assigned.
     */
     public Drawable getDrawable() {
+        if (mDrawable == mRecycleableBitmapDrawable) {
+            // Consider our cached version dirty since app code now has a reference to it
+            mRecycleableBitmapDrawable = null;
+        }
         return mDrawable;
     }
 
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 98bfd7d..50569d7 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -678,7 +678,7 @@
         void startScroll(int start, int distance, int duration) {
             mFinished = false;
 
-            mStart = start;
+            mCurrentPosition = mStart = start;
             mFinal = start + distance;
 
             mStartTime = AnimationUtils.currentAnimationTimeMillis();
@@ -712,7 +712,7 @@
         boolean springback(int start, int min, int max) {
             mFinished = true;
 
-            mStart = mFinal = start;
+            mCurrentPosition = mStart = mFinal = start;
             mVelocity = 0;
 
             mStartTime = AnimationUtils.currentAnimationTimeMillis();
@@ -804,7 +804,7 @@
             final float totalDuration = (float) Math.sqrt(
                     2.0 * (distanceToApex + distanceToEdge) / Math.abs(mDeceleration));
             mStartTime -= (int) (1000.0f * (totalDuration - durationToApex));
-            mStart = end;
+            mCurrentPosition = mStart = end;
             mVelocity = (int) (- mDeceleration * totalDuration);
         }
 
@@ -873,7 +873,7 @@
                     // Duration from start to null velocity
                     if (mDuration < mSplineDuration) {
                         // If the animation was clamped, we reached the edge
-                        mStart = mFinal;
+                        mCurrentPosition = mStart = mFinal;
                         // TODO Better compute speed when edge was reached
                         mVelocity = (int) mCurrVelocity;
                         mDeceleration = getDeceleration(mVelocity);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index b4cbf35..f9fa027 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -105,7 +105,10 @@
     /** View that handles event dispatch and content transitions. */
     private PopupDecorView mDecorView;
 
-    /** The contents of the popup. */
+    /** View that holds the background and may animate during a transition. */
+    private View mBackgroundView;
+
+    /** The contents of the popup. May be identical to the background view. */
     private View mContentView;
 
     private boolean mFocusable;
@@ -1111,18 +1114,18 @@
         if (aboveAnchor != mAboveAnchor) {
             mAboveAnchor = aboveAnchor;
 
-            if (mBackground != null) {
-                // If the background drawable provided was a StateListDrawable with above-anchor
-                // and below-anchor states, use those. Otherwise rely on refreshDrawableState to
-                // do the job.
+            if (mBackground != null && mBackgroundView != null) {
+                // If the background drawable provided was a StateListDrawable
+                // with above-anchor and below-anchor states, use those.
+                // Otherwise, rely on refreshDrawableState to do the job.
                 if (mAboveAnchorBackgroundDrawable != null) {
                     if (mAboveAnchor) {
-                        mDecorView.setBackground(mAboveAnchorBackgroundDrawable);
+                        mBackgroundView.setBackground(mAboveAnchorBackgroundDrawable);
                     } else {
-                        mDecorView.setBackground(mBelowAnchorBackgroundDrawable);
+                        mBackgroundView.setBackground(mBelowAnchorBackgroundDrawable);
                     }
                 } else {
-                    mDecorView.refreshDrawableState();
+                    mBackgroundView.refreshDrawableState();
                 }
             }
         }
@@ -1164,22 +1167,21 @@
 
         // When a background is available, we embed the content view within
         // another view that owns the background drawable.
-        final View backgroundView;
         if (mBackground != null) {
-            backgroundView = createBackgroundView(mContentView);
-            backgroundView.setBackground(mBackground);
+            mBackgroundView = createBackgroundView(mContentView);
+            mBackgroundView.setBackground(mBackground);
         } else {
-            backgroundView = mContentView;
+            mBackgroundView = mContentView;
         }
 
-        mDecorView = createDecorView(backgroundView);
+        mDecorView = createDecorView(mBackgroundView);
 
         // The background owner should be elevated so that it casts a shadow.
-        backgroundView.setElevation(mElevation);
+        mBackgroundView.setElevation(mElevation);
 
         // We may wrap that in another view, so we'll need to manually specify
         // the surface insets.
-        final int surfaceInset = (int) Math.ceil(backgroundView.getZ() * 2);
+        final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
         p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
         p.hasManualSurfaceInsets = true;
 
@@ -1650,6 +1652,7 @@
         // This needs to stay until after all transitions have ended since we
         // need the reference to cancel transitions in preparePopup().
         mDecorView = null;
+        mBackgroundView = null;
         mIsTransitioningToDismiss = false;
     }
 
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index d954b71..55493c3 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -28,6 +28,7 @@
 public class MetricsLogger implements MetricsConstants {
     // Temporary constants go here, to await migration to MetricsConstants.
     // next value is 239;
+    public static final int ACTION_ASSIST_LONG_PRESS = 239;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4f42ed9..6c7e298 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -7674,6 +7674,7 @@
             final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
 
             long leftOverRxTimeMs = rxTimeMs;
+            long leftOverTxTimeMs = txTimeMs;
 
             if (DEBUG_ENERGY) {
                 Slog.d(TAG, "------ BEGIN WiFi power blaming ------");
@@ -7705,6 +7706,10 @@
                 Slog.d(TAG, "  !Estimated scan time > Actual rx time (" + totalScanTimeMs + " ms > "
                         + rxTimeMs + " ms). Normalizing scan time.");
             }
+            if (DEBUG_ENERGY && totalScanTimeMs > txTimeMs) {
+                Slog.d(TAG, "  !Estimated scan time > Actual tx time (" + totalScanTimeMs + " ms > "
+                        + txTimeMs + " ms). Normalizing scan time.");
+            }
 
             // Actually assign and distribute power usage to apps.
             for (int i = 0; i < uidStatsSize; i++) {
@@ -7716,23 +7721,34 @@
                     // Set the new mark so that next time we get new data since this point.
                     uid.mWifiScanTimer.setMark(elapsedRealtimeMs);
 
+                    long scanRxTimeSinceMarkMs = scanTimeSinceMarkMs;
+                    long scanTxTimeSinceMarkMs = scanTimeSinceMarkMs;
+
+                    // Our total scan time is more than the reported Tx/Rx time.
+                    // This is possible because the cost of a scan is approximate.
+                    // Let's normalize the result so that we evenly blame each app
+                    // scanning.
+                    //
+                    // This means that we may have apps that transmitted/received packets not be
+                    // blamed for this, but this is fine as scans are relatively more expensive.
                     if (totalScanTimeMs > rxTimeMs) {
-                        // Our total scan time is more than the reported Rx time.
-                        // This is possible because the cost of a scan is approximate.
-                        // Let's normalize the result so that we evenly blame each app
-                        // scanning.
-                        //
-                        // This means that we may have apps that received packets not be blamed
-                        // for this, but this is fine as scans are relatively more expensive.
-                        scanTimeSinceMarkMs = (rxTimeMs * scanTimeSinceMarkMs) / totalScanTimeMs;
+                        scanRxTimeSinceMarkMs = (rxTimeMs * scanRxTimeSinceMarkMs) /
+                                totalScanTimeMs;
+                    }
+                    if (totalScanTimeMs > txTimeMs) {
+                        scanTxTimeSinceMarkMs = (txTimeMs * scanTxTimeSinceMarkMs) /
+                                totalScanTimeMs;
                     }
 
                     if (DEBUG_ENERGY) {
-                        Slog.d(TAG, "  ScanTime for UID " + uid.getUid() + ": "
-                                + scanTimeSinceMarkMs + " ms)");
+                        Slog.d(TAG, "  ScanTime for UID " + uid.getUid() + ": Rx:"
+                                + scanRxTimeSinceMarkMs + " ms  Tx:"
+                                + scanTxTimeSinceMarkMs + " ms)");
                     }
-                    uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanTimeSinceMarkMs);
-                    leftOverRxTimeMs -= scanTimeSinceMarkMs;
+                    uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanRxTimeSinceMarkMs);
+                    uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, scanTxTimeSinceMarkMs);
+                    leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
+                    leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
                 }
 
                 // Distribute evenly the power consumed while Idle to each app holding a WiFi
@@ -7755,12 +7771,14 @@
 
             if (DEBUG_ENERGY) {
                 Slog.d(TAG, "  New RxPower: " + leftOverRxTimeMs + " ms");
+                Slog.d(TAG, "  New TxPower: " + leftOverTxTimeMs + " ms");
             }
 
-            // Distribute the Tx power appropriately between all apps that transmitted packets.
+            // Distribute the remaining Tx power appropriately between all apps that transmitted
+            // packets.
             for (int i = 0; i < txPackets.size(); i++) {
                 final Uid uid = getUidStatsLocked(txPackets.keyAt(i));
-                final long myTxTimeMs = (txPackets.valueAt(i) * txTimeMs) / totalTxPackets;
+                final long myTxTimeMs = (txPackets.valueAt(i) * leftOverTxTimeMs) / totalTxPackets;
                 if (DEBUG_ENERGY) {
                     Slog.d(TAG, "  TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
                 }
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index da98a67..146c0f8 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -57,6 +57,11 @@
                 statsType);
         app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
                 statsType);
+
+        if (DEBUG && app.wifiPowerMah != 0) {
+            Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime + "ms tx=" +
+                    txTime + "ms power=" + BatteryStatsHelper.makemAh(app.wifiPowerMah));
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java
index c4e2ef6..3bd79f7e 100644
--- a/core/java/com/android/internal/os/WifiPowerEstimator.java
+++ b/core/java/com/android/internal/os/WifiPowerEstimator.java
@@ -16,11 +16,14 @@
 package com.android.internal.os;
 
 import android.os.BatteryStats;
+import android.util.Log;
 
 /**
  * Estimates WiFi power usage based on timers in BatteryStats.
  */
 public class WifiPowerEstimator extends PowerCalculator {
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+    private static final String TAG = "WifiPowerEstimator";
     private final double mWifiPowerPerPacket;
     private final double mWifiPowerOn;
     private final double mWifiPowerScan;
@@ -75,6 +78,10 @@
         }
 
         app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
+        if (DEBUG && app.wifiPowerMah != 0) {
+            Log.d(TAG, "UID " + u.getUid() + ": power=" +
+                    BatteryStatsHelper.makemAh(app.wifiPowerMah));
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2b39528..0bd8d85 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -72,6 +72,7 @@
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorContentParent;
 import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.NonClientDecorView;
 import com.android.internal.widget.SwipeDismissLayout;
 
 import android.app.ActivityManager;
@@ -1270,7 +1271,7 @@
      * @param st The panel being initialized.
      */
     protected boolean initializePanelDecor(PanelFeatureState st) {
-        st.decorView = new DecorView(getContext(), st.featureId);
+        st.decorView = generateDecor(st.featureId);
         st.gravity = Gravity.CENTER | Gravity.BOTTOM;
         st.setStyle(getContext());
         TypedArray a = getContext().obtainStyledAttributes(null,
@@ -2204,6 +2205,9 @@
 
         private final Rect mFrameOffsets = new Rect();
 
+        // True if a non client area decor exists.
+        private boolean mHasNonClientDecor = false;
+
         private boolean mChanging;
 
         private Drawable mMenuBackground;
@@ -3148,53 +3152,59 @@
                 return;
             }
 
-            setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top
-                    + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,
+            setPadding(mFramePadding.left + mBackgroundPadding.left,
+                    mFramePadding.top + mBackgroundPadding.top,
+                    mFramePadding.right + mBackgroundPadding.right,
                     mFramePadding.bottom + mBackgroundPadding.bottom);
             requestLayout();
             invalidate();
 
             int opacity = PixelFormat.OPAQUE;
-            // Note: if there is no background, we will assume opaque. The
-            // common case seems to be that an application sets there to be
-            // no background so it can draw everything itself. For that,
-            // we would like to assume OPAQUE and let the app force it to
-            // the slower TRANSLUCENT mode if that is really what it wants.
-            Drawable bg = getBackground();
-            Drawable fg = getForeground();
-            if (bg != null) {
-                if (fg == null) {
-                    opacity = bg.getOpacity();
-                } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
-                        && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
-                    // If the frame padding is zero, then we can be opaque
-                    // if either the frame -or- the background is opaque.
-                    int fop = fg.getOpacity();
-                    int bop = bg.getOpacity();
-                    if (false)
-                        Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
-                    if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
-                        opacity = PixelFormat.OPAQUE;
-                    } else if (fop == PixelFormat.UNKNOWN) {
-                        opacity = bop;
-                    } else if (bop == PixelFormat.UNKNOWN) {
-                        opacity = fop;
+            if (windowHasShadow()) {
+                // If the window has a shadow, it must be translucent.
+                opacity = PixelFormat.TRANSLUCENT;
+            } else{
+                // Note: If there is no background, we will assume opaque. The
+                // common case seems to be that an application sets there to be
+                // no background so it can draw everything itself. For that,
+                // we would like to assume OPAQUE and let the app force it to
+                // the slower TRANSLUCENT mode if that is really what it wants.
+                Drawable bg = getBackground();
+                Drawable fg = getForeground();
+                if (bg != null) {
+                    if (fg == null) {
+                        opacity = bg.getOpacity();
+                    } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
+                            && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
+                        // If the frame padding is zero, then we can be opaque
+                        // if either the frame -or- the background is opaque.
+                        int fop = fg.getOpacity();
+                        int bop = bg.getOpacity();
+                        if (false)
+                            Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
+                        if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
+                            opacity = PixelFormat.OPAQUE;
+                        } else if (fop == PixelFormat.UNKNOWN) {
+                            opacity = bop;
+                        } else if (bop == PixelFormat.UNKNOWN) {
+                            opacity = fop;
+                        } else {
+                            opacity = Drawable.resolveOpacity(fop, bop);
+                        }
                     } else {
-                        opacity = Drawable.resolveOpacity(fop, bop);
+                        // For now we have to assume translucent if there is a
+                        // frame with padding... there is no way to tell if the
+                        // frame and background together will draw all pixels.
+                        if (false)
+                            Log.v(TAG, "Padding: " + mFramePadding);
+                        opacity = PixelFormat.TRANSLUCENT;
                     }
-                } else {
-                    // For now we have to assume translucent if there is a
-                    // frame with padding... there is no way to tell if the
-                    // frame and background together will draw all pixels.
-                    if (false)
-                        Log.v(TAG, "Padding: " + mFramePadding);
-                    opacity = PixelFormat.TRANSLUCENT;
                 }
+                if (false)
+                    Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
             }
 
             if (false)
-                Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
-            if (false)
                 Log.v(TAG, "Selected default opacity: " + opacity);
 
             mDefaultOpacity = opacity;
@@ -3401,8 +3411,7 @@
                         }
                     };
                 } else {
-                    ViewStub stub = (ViewStub) findViewById(
-                            R.id.action_mode_bar_stub);
+                    ViewStub stub = (ViewStub) findViewById(R.id.action_mode_bar_stub);
                     if (stub != null) {
                         mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
                     }
@@ -3490,6 +3499,28 @@
                 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
         }
 
+        // Set when the window is free floating and a non client decor frame was added.
+        void enableNonClientDecor(boolean enable) {
+            if (mHasNonClientDecor != enable) {
+                mHasNonClientDecor = enable;
+                if (getForeground() != null) {
+                    drawableChanged();
+                }
+            }
+        }
+
+        // Returns true if the window has a non client decor.
+        private boolean windowHasNonClientDecor() {
+            return mHasNonClientDecor;
+        }
+
+        // Returns true if the Window is free floating and has a shadow. Note that non overlapping
+        // windows do not have a shadow since it could not be seen anyways (a small screen / tablet
+        // "tiles" the windows side by side but does not overlap them).
+        private boolean windowHasShadow() {
+            return windowHasNonClientDecor() && getElevation() > 0;
+        }
+
         /**
          * Clears out internal references when the action mode is destroyed.
          */
@@ -3599,8 +3630,8 @@
         }
     }
 
-    protected DecorView generateDecor() {
-        return new DecorView(getContext(), -1);
+    protected DecorView generateDecor(int featureId) {
+        return new DecorView(getContext(), featureId);
     }
 
     protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
@@ -3879,8 +3910,15 @@
 
         mDecor.startChanging();
 
+        NonClientDecorView nonClientDecorView = createNonClientDecorView();
         View in = mLayoutInflater.inflate(layoutResource, null);
-        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        if (nonClientDecorView != null) {
+            decor.addView(nonClientDecorView,
+                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            nonClientDecorView.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        } else {
+            decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        }
         mContentRoot = (ViewGroup) in;
 
         ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
@@ -3936,6 +3974,54 @@
         return contentParent;
     }
 
+    // Free floating overlapping windows require a non client decor with a caption and shadow..
+    private NonClientDecorView createNonClientDecorView() {
+        boolean needsDecor = true;
+        NonClientDecorView nonClientDecorView = null;
+
+        final WindowManager.LayoutParams attrs = getAttributes();
+        // TODO(skuhne): Use the associated stack to figure out if the window is on the free style
+        // desktop, the side by side desktop or the full screen desktop. With that informations the
+        // choice is fairly easy to decide.
+        // => This is only a kludge for now to suppress fullscreen windows, recents, launcher, etc..
+        boolean isFullscreen =
+                0 != ((mDecor.getWindowSystemUiVisibility() | mDecor.getSystemUiVisibility()) &
+                        (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION));
+        boolean isApplication = attrs.type != TYPE_BASE_APPLICATION &&
+                attrs.type != TYPE_APPLICATION;
+
+        // We do not show the non client decor if...
+        // - this is a floating dialog (which is not a real window, e.g. it cannot be maximized).
+        // - it is not an application (special windows have special functions, e.g text selector).
+        // - the application is full screen, drawing everything (since the decor would be out of the
+        //   screen in that case and could not be seen).
+        if (isFloating() || isFullscreen || isApplication) {
+            needsDecor = false;
+        }
+
+        if (needsDecor) {
+            // TODO(skuhne): If running in side by side mode on a device - turn off the shadow.
+            boolean windowHasShadow = true;
+            // Dependent on the brightness of the used title we either use the
+            // dark or the light button frame.
+            TypedValue value = new TypedValue();
+            getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+            if (Color.brightness(value.data) < 0.5) {
+                nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+                        R.layout.non_client_decor_dark, null);
+            } else {
+                nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+                        R.layout.non_client_decor_light, null);
+            }
+            nonClientDecorView.setPhoneWindow(this, windowHasShadow);
+        }
+
+        // Tell the Decor if it has a non client decor.
+        mDecor.enableNonClientDecor(needsDecor);
+
+        return nonClientDecorView;
+    }
+
     /** @hide */
     public void alwaysReadCloseOnTouchAttr() {
         mAlwaysReadCloseOnTouchAttr = true;
@@ -3943,7 +4029,7 @@
 
     private void installDecor() {
         if (mDecor == null) {
-            mDecor = generateDecor();
+            mDecor = generateDecor(-1);
             mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
             mDecor.setIsRootNamespace(true);
             if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
new file mode 100644
index 0000000..57039b7
--- /dev/null
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.util.Log;
+import android.util.TypedValue;
+
+import android.view.ViewOutlineProvider;
+import android.view.WindowInsets;
+import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow;
+
+import java.util.List;
+
+/**
+ * This class represents the special screen elements to control a window on free form
+ * environment. All thse screen elements are added in the "non client area" which is the area of
+ * the window which is handled by the OS and not the application.
+ * As such this class handles the following things:
+ * <ul>
+ * <li>The caption, containing the system buttons like maximize, close and such as well as
+ * allowing the user to drag the window around.</li>
+ * <li>The shadow - which is changing dependent on the window focus.</li>
+ * <li>The border around the client area (if there is one).</li>
+ * <li>The resize handles which allow to resize the window.</li>
+ * </ul>
+ * After creating the view, the function
+ * {@link #setPhoneWindow(PhoneWindow owner, boolean windowHasShadow)} needs to be called to make
+ * the connection to it's owning PhoneWindow.
+ * Note: At this time the application can change various attributes of the DecorView which
+ * will break things (in settle/unexpected ways):
+ * <ul>
+ * <li>setElevation</li>
+ * <li>setOutlineProvider</li>
+ * <li>setSurfaceFormat</li>
+ * <li>..</li>
+ * </ul>
+ * This will be mitigated once b/22527834 will be addressed.
+ */
+public class NonClientDecorView extends ViewGroup implements View.OnClickListener {
+    private final static String TAG = "NonClientDecorView";
+    // The height of a window which has focus in DIP.
+    private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
+    // The height of a window which has not in DIP.
+    private final int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
+
+    private PhoneWindow mOwner = null;
+    boolean mWindowHasShadow = false;
+
+    // The current focus state of the window for updating the window elevation.
+    boolean mWindowHasFocus = true;
+
+    // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
+    // size calculation takes the shadow size into account. We set the elevation currently
+    // to max until the first layout command has been executed.
+    boolean mAllowUpdateElevation = false;
+
+    public NonClientDecorView(Context context) {
+        super(context);
+    }
+
+    public NonClientDecorView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public NonClientDecorView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setPhoneWindow(PhoneWindow owner, boolean windowHasShadow) {
+        mOwner = owner;
+        mWindowHasShadow = windowHasShadow;
+        if (mWindowHasShadow) {
+            // TODO(skuhne): Call setMaxElevation here as soon as b/22668382 got fixed.
+            updateElevation();
+        }
+        // By changing the outline provider to BOUNDS, the window can remove its
+        // background without removing the shadow.
+        mOwner.getDecorView().setOutlineProvider(ViewOutlineProvider.BOUNDS);
+        findViewById(R.id.maximize_window).setOnClickListener(this);
+        findViewById(R.id.close_window).setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (view.getId() == R.id.maximize_window) {
+            // TODO(skuhne): Add code to maximize window.
+        } else if (view.getId() == R.id.close_window) {
+            // TODO(skuhne): This is not the right way to kill an app and we should add a high level
+            // function for it.
+            final ActivityManager m =
+                    (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
+            List<RunningTaskInfo> runningTaskInfoList =  m.getRunningTasks(1);
+            if (!runningTaskInfoList.isEmpty()) {
+                try {
+                    ActivityManagerNative.getDefault().removeTask(runningTaskInfoList.get(0).id);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Couldn't close task with the close button.");
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        mWindowHasFocus = hasWindowFocus;
+        updateElevation();
+        super.onWindowFocusChanged(hasWindowFocus);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        measureChildren(widthMeasureSpec, heightMeasureSpec);
+        final int width = MeasureSpec.getSize(widthMeasureSpec);
+        final int height = MeasureSpec.getSize(heightMeasureSpec);
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        // The system inset needs only to be applied to the caption. The client area of
+        // the window will automatically be adjusted by the the DecorView.
+        WindowInsets insets = getRootWindowInsets();
+        int systemMargin = insets.getSystemWindowInsetTop();
+
+        final int leftPos = getPaddingLeft();
+        final int rightPos = right - left - getPaddingRight();
+        final int topPos = getPaddingTop();
+        final int bottomPos = bottom - top - getPaddingBottom();
+
+        // On top we have the caption which has to fill left to right with a fixed height.
+        final int width = rightPos - leftPos;
+        final View caption = getChildAt(0);
+
+        // If the application changed its SystemUI metrics, we might also have to adapt
+        // our shadow elevation.
+        updateElevation();
+        mAllowUpdateElevation = true;
+
+        // Remove the decor temporarily if the window entered a full screen/immersive mode.
+        final int captionHeight = isFillingScreen() ? 0 : caption.getMeasuredHeight();
+        caption.layout(leftPos, topPos + systemMargin, leftPos + width,
+                topPos + systemMargin + captionHeight);
+
+        // Note: We should never have more then 1 additional item in here.
+        if (getChildCount() > 1) {
+            getChildAt(1).layout(leftPos, topPos + captionHeight, leftPos + width, bottomPos);
+        }
+    }
+
+    // Make sure that we never get more then one client area in our view.
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        if (index >= 2 || getChildCount() >= 2) {
+            throw new IllegalStateException("NonClientDecorView can only handle 1 client view");
+        }
+        super.addView(child, index, params);
+    }
+
+    // Returns true when the window is filling the entire screen and the non client area
+    // should not be shown.
+    private boolean isFillingScreen() {
+        return (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility()) &
+                (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+                        View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE)));
+    }
+
+    // The shadow height gets controlled by the focus to visualize highlighted windows.
+    // Note: This will overwrite application elevation properties.
+    // Note: Windows which have (temporarily) changed their attributes to cover the SystemUI
+    //       will get no shadow as they are expected to be "full screen".
+    private void updateElevation() {
+        float elevation = 0;
+        if (mWindowHasShadow) {
+            boolean fill = isFillingScreen();
+            elevation = fill ? 0 :
+                    (mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP :
+                            DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP);
+            if (!mAllowUpdateElevation && !fill) {
+                // TODO(skuhne): Change this to setMaxElevation as soon as b/22668382 got fixed
+                // and remove this cludge.
+                elevation = DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
+            }
+            // Convert the DP elevation into physical pixels.
+            elevation = dipToPx(elevation);
+        }
+        // Don't change the elevation if it didn't change since it can require some time.
+        if (mOwner.getDecorView().getElevation() != elevation) {
+            mOwner.setElevation(elevation);
+        }
+    }
+
+    private float dipToPx(float dip) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
+                getResources().getDisplayMetrics());
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 6b07a47..fc15b964 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -20,6 +20,10 @@
     LOCAL_CFLAGS += -DENABLE_CPUSETS
 endif
 
+ifneq ($(ENABLE_SCHED_BOOST),)
+    LOCAL_CFLAGS += -DENABLE_SCHED_BOOST
+endif
+
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
 LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index db88962..4c920dc 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -298,11 +298,11 @@
 
     String8 storageSource;
     if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
-        storageSource = "/mnt/runtime_default";
+        storageSource = "/mnt/runtime/default";
     } else if (mount_mode == MOUNT_EXTERNAL_READ) {
-        storageSource = "/mnt/runtime_read";
+        storageSource = "/mnt/runtime/read";
     } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
-        storageSource = "/mnt/runtime_write";
+        storageSource = "/mnt/runtime/write";
     } else {
         // Sane default of no storage visible
         return true;
@@ -408,6 +408,27 @@
   }
 }
 
+#ifdef ENABLE_SCHED_BOOST
+static void SetForkLoad(bool boost) {
+  // set scheduler knob to boost forked processes
+  pid_t currentPid = getpid();
+  // fits at most "/proc/XXXXXXX/sched_init_task_load\0"
+  char schedPath[35];
+  snprintf(schedPath, sizeof(schedPath), "/proc/%u/sched_init_task_load", currentPid);
+  int schedBoostFile = open(schedPath, O_WRONLY);
+  if (schedBoostFile < 0) {
+    ALOGW("Unable to set zygote scheduler boost");
+    return;
+  }
+  if (boost) {
+    write(schedBoostFile, "100\0", 4);
+  } else {
+    write(schedBoostFile, "0\0", 2);
+  }
+  close(schedBoostFile);
+}
+#endif
+
 // Utility routine to fork zygote and specialize the child process.
 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                      jint debug_flags, jobjectArray javaRlimits,
@@ -418,6 +439,10 @@
                                      jstring instructionSet, jstring dataDir) {
   SetSigChldHandler();
 
+#ifdef ENABLE_SCHED_BOOST
+  SetForkLoad(true);
+#endif
+
   pid_t pid = fork();
 
   if (pid == 0) {
@@ -558,6 +583,12 @@
     }
   } else if (pid > 0) {
     // the parent process
+
+#ifdef ENABLE_SCHED_BOOST
+    // unset scheduler knob
+    SetForkLoad(false);
+#endif
+
   }
   return pid;
 }
diff --git a/core/res/res/drawable/decor_close_button_dark.xml b/core/res/res/drawable/decor_close_button_dark.xml
new file mode 100644
index 0000000..e5ea1f3
--- /dev/null
+++ b/core/res/res/drawable/decor_close_button_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_close_button_dark_focused" />
+    <item android:drawable="@drawable/ic_decor_close_button_dark_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/decor_close_button_light.xml b/core/res/res/drawable/decor_close_button_light.xml
new file mode 100644
index 0000000..b77b2bd
--- /dev/null
+++ b/core/res/res/drawable/decor_close_button_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_close_button_light_focused" />
+    <item android:drawable="@drawable/ic_decor_close_button_light_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/decor_maximize_button_dark.xml b/core/res/res/drawable/decor_maximize_button_dark.xml
new file mode 100644
index 0000000..5ea372b
--- /dev/null
+++ b/core/res/res/drawable/decor_maximize_button_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_maximize_button_dark_focused" />
+    <item android:drawable="@drawable/ic_decor_maximize_button_dark_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/decor_maximize_button_light.xml b/core/res/res/drawable/decor_maximize_button_light.xml
new file mode 100644
index 0000000..5bda131
--- /dev/null
+++ b/core/res/res/drawable/decor_maximize_button_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_maximize_button_light_focused" />
+    <item android:drawable="@drawable/ic_decor_maximize_button_light_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_focused.xml b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
new file mode 100644
index 0000000..d7b167dd
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
new file mode 100644
index 0000000..e2e81b9
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33FFFFFF"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_focused.xml b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
new file mode 100644
index 0000000..0794ed3
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#ff000000"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
new file mode 100644
index 0000000..bd1db51
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33000000"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
new file mode 100644
index 0000000..73d808b
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#B2FFFFFF"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
new file mode 100644
index 0000000..dc79e10
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33FFFFFF"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#33FFFFFF"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
new file mode 100644
index 0000000..c23390e
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#FF000000"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#B2000000"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
new file mode 100644
index 0000000..a194a39
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33000000"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#33000000"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/non_client_decor_title.xml b/core/res/res/drawable/non_client_decor_title.xml
new file mode 100644
index 0000000..e50daea
--- /dev/null
+++ b/core/res/res/drawable/non_client_decor_title.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/non_client_decor_title_focused" />
+    <item android:drawable="@drawable/non_client_decor_title_unfocused" />
+</selector>
diff --git a/core/res/res/drawable/non_client_decor_title_focused.xml b/core/res/res/drawable/non_client_decor_title_focused.xml
new file mode 100644
index 0000000..7d1c230
--- /dev/null
+++ b/core/res/res/drawable/non_client_decor_title_focused.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<shape android:shape="rectangle"
+       android:tintMode="multiply"
+       android:tint="#D8D8D8"
+       xmlns:android="http://schemas.android.com/apk/res/android">
+     <!-- Fading the primary color to 85% blackness -->
+     <solid android:color="?android:attr/colorPrimary" />
+</shape>
diff --git a/core/res/res/drawable/non_client_decor_title_unfocused.xml b/core/res/res/drawable/non_client_decor_title_unfocused.xml
new file mode 100644
index 0000000..2846d8ca
--- /dev/null
+++ b/core/res/res/drawable/non_client_decor_title_unfocused.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<shape android:shape="rectangle"
+       android:tintMode="multiply"
+       android:tint="#F2F2F2"
+       xmlns:android="http://schemas.android.com/apk/res/android">
+     <!-- Fading the primary color to 95% blackness -->
+     <solid android:color="?android:attr/colorPrimary"/>
+</shape>
diff --git a/core/res/res/layout/non_client_decor_dark.xml b/core/res/res/layout/non_client_decor_dark.xml
new file mode 100644
index 0000000..00b4255
--- /dev/null
+++ b/core/res/res/layout/non_client_decor_dark.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, 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.
+*/
+-->
+
+<com.android.internal.widget.NonClientDecorView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|start"
+    android:descendantFocusability="beforeDescendants" >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_gravity="end"
+        android:layout_height="wrap_content"
+        android:background="@drawable/non_client_decor_title" >
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+        <Button
+            android:id="@+id/maximize_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/maximize_button_text"
+            android:background="@drawable/decor_maximize_button_dark" />
+         <Button
+            android:id="@+id/close_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/close_button_text"
+            android:background="@drawable/decor_close_button_dark" />
+    </LinearLayout>
+</com.android.internal.widget.NonClientDecorView>
diff --git a/core/res/res/layout/non_client_decor_light.xml b/core/res/res/layout/non_client_decor_light.xml
new file mode 100644
index 0000000..0ce8fa7
--- /dev/null
+++ b/core/res/res/layout/non_client_decor_light.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, 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.
+*/
+-->
+
+<com.android.internal.widget.NonClientDecorView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|start"
+    android:descendantFocusability="beforeDescendants" >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_gravity="end"
+        android:layout_height="wrap_content"
+        android:background="@drawable/non_client_decor_title" >
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+        <Button
+            android:id="@+id/maximize_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/maximize_button_text"
+            android:background="@drawable/decor_maximize_button_light" />
+         <Button
+            android:id="@+id/close_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/close_button_text"
+            android:background="@drawable/decor_close_button_light" />
+    </LinearLayout>
+</com.android.internal.widget.NonClientDecorView>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 351a4f1..5045f46 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -628,7 +628,7 @@
     <string name="relationTypeFather" msgid="5228034687082050725">"পিতা"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"বন্ধু"</string>
     <string name="relationTypeManager" msgid="6365677861610137895">"ম্যানেজার"</string>
-    <string name="relationTypeMother" msgid="4578571352962758304">"মাতা"</string>
+    <string name="relationTypeMother" msgid="4578571352962758304">"মা"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"পিতা ও মাতা"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"অংশীদার"</string>
     <string name="relationTypeReferredBy" msgid="101573059844135524">"এর দ্বারা নির্দেশ করা"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a5c70ea..3f38360 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -713,7 +713,7 @@
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"S\'ha afegit una cel·la"</string>
     <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"S\'ha afegit la cel·la <xliff:g id="CELL_INDEX">%1$s</xliff:g>"</string>
     <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Patró completat"</string>
-    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Àrea de patró"</string>
+    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Àrea del patró."</string>
     <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Afegeix un widget"</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Buit"</string>
@@ -898,7 +898,7 @@
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> s\'ha aturat."</string>
     <string name="aerr_process" msgid="4507058997035697579">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> s\'ha aturat."</string>
-    <string name="aerr_process_silence" msgid="4226685530196000222">"Fins que no reiniciïs l\'aplicació, la funció de silenci fallarà a causa de: <xliff:g id="PROCESS">%1$s</xliff:g>."</string>
+    <string name="aerr_process_silence" msgid="4226685530196000222">"Silencia la informació de bloqueig de l\'aplicació <xliff:g id="PROCESS">%1$s</xliff:g> fins que es reiniciï."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> no respon.\n\nVols tancar-la?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"L\'activitat <xliff:g id="ACTIVITY">%1$s</xliff:g> no respon.\n\nVols tancar-la?"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index dff15d5..18c52b1 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -713,7 +713,7 @@
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Cellule ajoutée."</string>
     <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"Cellule <xliff:g id="CELL_INDEX">%1$s</xliff:g> ajoutée"</string>
     <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Schéma terminé."</string>
-    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Zone du schéma"</string>
+    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Zone du motif"</string>
     <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ajouter un widget"</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vide"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index e3238e8..82d8452 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1026,7 +1026,7 @@
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver máis opcións."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar a depuración de erros de USB."</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para desactivala"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
     <string name="show_ime" msgid="9157568568695230830">"Mostra método de entrada"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1523bde..fd87a65 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -713,7 +713,7 @@
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"कक्ष जोड़ा गया"</string>
     <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"सेल <xliff:g id="CELL_INDEX">%1$s</xliff:g> जोड़ा गया"</string>
     <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"आकार पूरा किया गया"</string>
-    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"आकार क्षेत्र."</string>
+    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"प्रतिमान क्षेत्र."</string>
     <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोड़ें"</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"खाली"</string>
diff --git a/core/res/res/values-mcc202-mnc05/config.xml b/core/res/res/values-mcc202-mnc05/config.xml
deleted file mode 100644
index c74f2d7..0000000
--- a/core/res/res/values-mcc202-mnc05/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-      <item>1</item>
-      <item>4</item>
-      <item>7</item>
-      <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type",
-         Or string format of ApnSettingV3.
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string-array translatable="false" name="config_tether_apndata">
-      <item>Vf Tethering,internet.vodafone.gr,,,,,,,,,202,05,,DUN</item>
-    </string-array>
-
-</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7a0a066..9bfa8e3 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -149,7 +149,7 @@
     <string name="httpErrorAuth" msgid="1435065629438044534">"Nu s-a realizat autentificarea."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autentificarea prin intermediul serverului proxy nu a reuşit."</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"Nu s-a putut stabili conexiunea cu serverul."</string>
-    <string name="httpErrorIO" msgid="2340558197489302188">"Nu s-a putut efectua comunicarea cu serverul. Încercaţi din nou mai târziu."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"Nu s-a putut efectua comunicarea cu serverul. Încercați din nou mai târziu."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Conexiunea la server a expirat."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Pagina conţine prea multe redirecţionări de server."</string>
     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protocolul nu este acceptat."</string>
@@ -157,7 +157,7 @@
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Pagina nu a putut fi deschisă, deoarece adresa URL nu este validă."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"Fişierul nu a putut fi accesat."</string>
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nu s-a putut găsi fişierul solicitat."</string>
-    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Există prea multe solicitări în curs de procesare. Încercaţi din nou mai târziu."</string>
+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Există prea multe solicitări în curs de procesare. Încercați din nou mai târziu."</string>
     <string name="notification_title" msgid="8967710025036163822">"Eroare de conectare pentru <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Sincronizare"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
@@ -182,7 +182,7 @@
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
     <string name="silent_mode" msgid="7167703389802618663">"Mod Silenţios"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Activați funcţia wireless"</string>
-    <string name="turn_off_radio" msgid="8198784949987062346">"Dezactivaţi funcţia wireless"</string>
+    <string name="turn_off_radio" msgid="8198784949987062346">"Dezactivați funcţia wireless"</string>
     <string name="screen_lock" msgid="799094655496098153">"Blocați ecranul"</string>
     <string name="power_off" msgid="4266614107412865048">"Opriți alimentarea"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Sonerie dezactivată"</string>
@@ -659,8 +659,8 @@
     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Urgență"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Reveniţi la apel"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Corect!"</string>
-    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Încercaţi din nou"</string>
-    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Încercaţi din nou"</string>
+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Încercați din nou"</string>
+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Încercați din nou"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depăşit numărul maxim de încercări pentru Deblocare facială"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Niciun card SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nu există card SIM în computerul tablet PC."</string>
@@ -683,19 +683,19 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultaţi Ghidul de utilizare sau contactaţi Serviciul de relaţii cu clienţii."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Cardul SIM este blocat."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Se deblochează cardul SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul datelor de conectare la Google.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va fi acum resetat la setările prestabilite din fabrică."</string>
-    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Încercaţi din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Încercați din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Aţi uitat modelul?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Deblocare cont"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Prea multe încercări de desenare a modelului"</string>
@@ -805,7 +805,7 @@
     <string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeţi interogarea"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
-    <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activaţi Exploraţi prin atingere?"</string>
+    <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Exploraţi prin atingere?"</string>
     <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu tableta."</string>
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu telefonul."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
@@ -903,7 +903,7 @@
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"Din păcate, <xliff:g id="APPLICATION">%1$s</xliff:g> s-a oprit."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Din păcate, procesul <xliff:g id="PROCESS">%1$s</xliff:g> s-a oprit."</string>
-    <string name="aerr_process_silence" msgid="4226685530196000222">"Silence se blochează din cauza procesului <xliff:g id="PROCESS">%1$s</xliff:g> până la repornire."</string>
+    <string name="aerr_process_silence" msgid="4226685530196000222">"Nu mai afișa blocările aplicației <xliff:g id="PROCESS">%1$s</xliff:g> până la repornire."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"Aplicaţia <xliff:g id="APPLICATION">%2$s</xliff:g> nu răspunde.\n\nDoriţi să o închideţi?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"Activitatea <xliff:g id="ACTIVITY">%1$s</xliff:g> nu răspunde.\n\nDoriţi să o închideţi?"</string>
@@ -1272,7 +1272,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greşită"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercaţi din nou peste <xliff:g id="NUMBER">%1$d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercați din nou peste <xliff:g id="NUMBER">%1$d</xliff:g> (de) secunde."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
@@ -1294,18 +1294,18 @@
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Se verifică contul…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a televizorului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, televizorul va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a televizorului. Televizorul va reveni acum la setările prestabilite din fabrică."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, vi se va solicita să deblocați televizorul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 26e4cc0..7795025 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -898,7 +898,7 @@
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"துரதிருஷ்டவசமாக, <xliff:g id="APPLICATION">%1$s</xliff:g> நிறுத்தப்பட்டது."</string>
     <string name="aerr_process" msgid="4507058997035697579">"துரதிருஷ்டவசமாக, <xliff:g id="PROCESS">%1$s</xliff:g> செயல்முறை நிறுத்தப்பட்டது."</string>
-    <string name="aerr_process_silence" msgid="4226685530196000222">"<xliff:g id="PROCESS">%1$s</xliff:g> இலிருந்து மறுதொடக்கம் செய்யும் வரை சைலன்ஸ் செயலிழந்தது."</string>
+    <string name="aerr_process_silence" msgid="4226685530196000222">"<xliff:g id="PROCESS">%1$s</xliff:g> இன் செயலிழப்புகளை மறுதொடக்கம் செய்யும் வரை தெரிவிக்காதே."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> பதிலளிக்கவில்லை.\n\nஇதை மூட விருப்பமா?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> செயல்பாடு பதிலளிக்கவில்லை.\n\nஇதை மூடவா?"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f64bf2c..4e17662 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -908,7 +908,7 @@
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"На жаль, програма <xliff:g id="APPLICATION">%1$s</xliff:g> припинила роботу."</string>
     <string name="aerr_process" msgid="4507058997035697579">"На жаль, програма <xliff:g id="PROCESS">%1$s</xliff:g> припинила роботу."</string>
-    <string name="aerr_process_silence" msgid="4226685530196000222">"Додаток Silence перестає працювати через <xliff:g id="PROCESS">%1$s</xliff:g>. Потрібно перезавантажувати пристрій."</string>
+    <string name="aerr_process_silence" msgid="4226685530196000222">"Не показувати інформацію про збої додатка <xliff:g id="PROCESS">%1$s</xliff:g> до перезавантаження."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"Програма <xliff:g id="APPLICATION">%2$s</xliff:g> не відповідає.\n\nЗакрити її?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"Дія <xliff:g id="ACTIVITY">%1$s</xliff:g> не відповідає.\n\nЗакінчити її?"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index b0f6883..1345673 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -713,7 +713,7 @@
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Katak qo‘shildi"</string>
     <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"<xliff:g id="CELL_INDEX">%1$s</xliff:g> katak qo‘shildi"</string>
     <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Chizma namunasi tugatildi"</string>
-    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Chizmali qulf maydoni."</string>
+    <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Chizmali kalit hududi."</string>
     <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidjet %2$d / %3$d."</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidjet qo‘shish."</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Bo‘sh"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 712272f..99beef8 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1810,6 +1810,10 @@
         <enum name="KEYCODE_STEM_1" value="265" />
         <enum name="KEYCODE_STEM_2" value="266" />
         <enum name="KEYCODE_STEM_3" value="267" />
+        <enum name="KEYCODE_DPAD_UP_LEFT" value="268" />
+        <enum name="KEYCODE_DPAD_DOWN_LEFT" value="269" />
+        <enum name="KEYCODE_DPAD_UP_RIGHT" value="270" />
+        <enum name="KEYCODE_DPAD_DOWN_RIGHT" value="271" />
     </attr>
 
     <!-- ***************************************************************** -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aa15b5a..398c584 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -505,16 +505,16 @@
     <bool translatable="false" name="config_wifi_ssid_white_list_enable">true</bool>
 
     <!-- Idle Receive current for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_idle_receive_cur_ma">1</integer>
+    <integer translatable="false" name="config_wifi_idle_receive_cur_ma">0</integer>
 
     <!-- Rx current for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_active_rx_cur_ma">2</integer>
+    <integer translatable="false" name="config_wifi_active_rx_cur_ma">0</integer>
 
     <!-- Tx current for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_tx_cur_ma">3</integer>
+    <integer translatable="false" name="config_wifi_tx_cur_ma">0</integer>
 
     <!-- Operating volatage for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_operating_voltage_mv">4</integer>
+    <integer translatable="false" name="config_wifi_operating_voltage_mv">0</integer>
 
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7cdad4b..ac6204d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4056,6 +4056,12 @@
     <!-- Content description for the button that closes the floating toolbar overflow. [CHAR LIMIT=NONE] -->
     <string name="floating_toolbar_close_overflow_description">Close overflow</string>
 
+    <!-- Free style window strings -->
+    <!-- Accessibility text for the maximize window button -->
+    <string name="maximize_button_text">Maximize</string>
+    <!-- Accessibility text for the close window button -->
+    <string name="close_button_text">Close</string>
+
     <!-- Ellipsis character to appear in notification templates, e.g.
          notification_template_material_inbox.xml.
          DO NOT TRANSLATE -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5303d5f..a45d907 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1939,6 +1939,10 @@
 
   <!-- From Phone -->
   <java-symbol type="bool" name="config_built_in_sip_phone" />
+  <java-symbol type="id" name="maximize_window" />
+  <java-symbol type="id" name="close_window" />
+  <java-symbol type="layout" name="non_client_decor_light" />
+  <java-symbol type="layout" name="non_client_decor_dark" />
 
   <!-- From TelephonyProvider -->
   <java-symbol type="xml" name="apns" />
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
index 89e32e4..dab7b90 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
@@ -21,10 +21,12 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.Suppress;
 import android.view.View;
 import android.view.KeyEvent;
 import com.android.frameworks.coretests.R;
 
+@Suppress // Flaky
 public class GlobalFocusChangeTest extends ActivityInstrumentationTestCase<GlobalFocusChange> {
     private GlobalFocusChange mActivity;
     private View mLeft;
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
index 1968a32..bec6f80 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
@@ -16,6 +16,7 @@
 
 package android.widget.focus;
 
+import android.test.suitebuilder.annotation.Suppress;
 import android.widget.focus.ListOfButtons;
 import com.android.frameworks.coretests.R;
 
@@ -31,6 +32,7 @@
  * Tests that focus works as expected when navigating into and out of
  * a {@link ListView} that has buttons in it.
  */
+@Suppress // Flaky
 public class ListOfButtonsTest extends ActivityInstrumentationTestCase2<ListOfButtons> {
 
     private ListAdapter mListAdapter;
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
index ddde48f..6ce4c15 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
@@ -16,6 +16,7 @@
 
 package android.widget.scroll.arrowscroll;
 
+import android.test.suitebuilder.annotation.Suppress;
 import android.widget.scroll.arrowscroll.MultiPageTextWithPadding;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -24,6 +25,7 @@
 import android.widget.TextView;
 import android.widget.ScrollView;
 
+@Suppress // Flaky
 public class MultiPageTextWithPaddingTest extends
         ActivityInstrumentationTestCase<MultiPageTextWithPadding> {
 
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 3181017..39458f9 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -17,10 +17,13 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# Use full Noto Sans Japanese font on non-smaller footprints
+# Use full Noto Sans Japanese font on the normal footprints, but
+# exclude it from SMALLER and use a subset on the CONSTRAINED ones.
 ifneq ($(SMALLER_FONT_FOOTPRINT),true)
+ifneq ($(CONSTRAINED_FONT_FOOTPRINT),true)
 FONT_NOTOSANS_JP_FULL := true
 endif
+endif
 
 ##########################################
 # create symlink for given font
@@ -82,19 +85,32 @@
 extra_font_files :=
 
 ################################
-# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT build
+# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT builds,
+# and the full font on CONSTRAINED_FONT_FOOTPRINT ones.
 ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+droidsans_fallback_src := DroidSansFallback.ttf
+build_droidsans_fallback := true
+endif  # SMALLER_FONT_FOOTPRINT
+
+ifeq ($(CONSTRAINED_FONT_FOOTPRINT),true)
+droidsans_fallback_src := DroidSansFallbackFull.ttf
+build_droidsans_fallback := true
+endif  # CONSTRAINED_FONT_FOOTPRINT
+
+ifeq ($(build_droidsans_fallback),true)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := DroidSansFallback.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_SRC_FILES := $(droidsans_fallback_src)
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
 include $(BUILD_PREBUILT)
 droidsans_fallback_src :=
 
-endif  # SMALLER_FONT_FOOTPRINT
+endif  # build_droidsans_fallback
+
+build_droidsans_fallback :=
 
 ################################
 # Build the rest of font files as prebuilt.
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index bdb1f58..fef65ee 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.util.SparseIntArray;
 
+import java.util.TreeSet;
+
 /**
  * Class to provide information about the audio devices.
  */
@@ -109,6 +111,14 @@
      * A device type connected over IP.
      */
     public static final int TYPE_IP               = 20;
+    /**
+     * @hide
+     * A remote-submix device.
+     * We need this for CTS, but it is not part of the external API.
+     * FIXME It has been suggested that CTS should only be testing public APIs.
+     *   Consider this for a public API.
+     */
+    public static final int TYPE_REMOTE_SUBMIX    = 0x7FFF;
 
     private final AudioDevicePort mPort;
 
@@ -156,6 +166,8 @@
 
     /**
      * @return An array of sample rates supported by the audio device.
+     *
+     * Note: an empty array indicates that the device supports arbitrary rates.
      */
     public @NonNull int[] getSampleRates() {
         return mPort.samplingRates();
@@ -166,6 +178,8 @@
      * {@link AudioFormat#CHANNEL_OUT_7POINT1}) for which this audio device can be configured.
      *
      * @see AudioFormat
+     *
+     * Note: an empty array indicates that the device supports arbitrary channel masks.
      */
     public @NonNull int[] getChannelMasks() {
         return mPort.channelMasks();
@@ -175,6 +189,8 @@
      * @return An array of channel index masks for which this audio device can be configured.
      *
      * @see AudioFormat
+     *
+     * Note: an empty array indicates that the device supports arbitrary channel index masks.
      */
     public @NonNull int[] getChannelIndexMasks() {
         return mPort.channelIndexMasks();
@@ -183,15 +199,28 @@
     /**
      * @return An array of channel counts (1, 2, 4, ...) for which this audio device
      * can be configured.
+     *
+     * Note: an empty array indicates that the device supports arbitrary channel counts.
      */
     public @NonNull int[] getChannelCounts() {
-        int[] masks = getChannelMasks();
-        int[] counts = new int[masks.length];
-        // TODO: consider channel index masks
-        for (int mask_index = 0; mask_index < masks.length; mask_index++) {
-            counts[mask_index] = isSink()
-                    ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
-                    : AudioFormat.channelCountFromInChannelMask(masks[mask_index]);
+        TreeSet<Integer> countSet = new TreeSet<Integer>();
+
+        // Channel Masks
+        for (int mask : getChannelMasks()) {
+            countSet.add(isSink() ?
+                    AudioFormat.channelCountFromOutChannelMask(mask)
+                    : AudioFormat.channelCountFromInChannelMask(mask));
+        }
+
+        // Index Masks
+        for (int index_mask : getChannelIndexMasks()) {
+            countSet.add(Integer.bitCount(index_mask));
+        }
+
+        int[] counts = new int[countSet.size()];
+        int index = 0;
+        for (int count : countSet) {
+            counts[index++] = count; 
         }
         return counts;
     }
@@ -205,6 +234,8 @@
      * integer precision to that device.
      *
      * @see AudioFormat
+     *
+     * Note: an empty array indicates that the device supports arbitrary encodings.
      */
     public @NonNull int[] getEncodings() {
         return AudioFormat.filterPublicFormats(mPort.formats());
@@ -255,6 +286,7 @@
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX);
 
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
@@ -272,10 +304,7 @@
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
         INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP);
-
-        // not covered here, legacy
-        //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
-        //AudioSystem.DEVICE_IN_REMOTE_SUBMIX
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX);
 
         // privileges mapping to output device
         EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray();
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index acdadd7..e99a37a 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -604,6 +604,10 @@
     public static final int SYNC_EVENT_NONE = 0;
     public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1;
 
+    /**
+     * @return command completion status, one of {@link #AUDIO_STATUS_OK},
+     *     {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED}
+     */
     public static native int setDeviceConnectionState(int device, int state,
                                                       String device_address, String device_name);
     public static native int getDeviceConnectionState(int device, String device_address);
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 89230fe..7197dc0 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -24,7 +24,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * This class is the public application interface to the MIDI service.
@@ -61,8 +61,8 @@
     private final IMidiManager mService;
     private final IBinder mToken = new Binder();
 
-    private HashMap<DeviceCallback,DeviceListener> mDeviceListeners =
-        new HashMap<DeviceCallback,DeviceListener>();
+    private ConcurrentHashMap<DeviceCallback,DeviceListener> mDeviceListeners =
+        new ConcurrentHashMap<DeviceCallback,DeviceListener>();
 
     // Binder stub for receiving device notifications from MidiService
     private class DeviceListener extends IMidiDeviceListener.Stub {
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 3eee55a..6b0816d 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -21,7 +21,7 @@
     <string name="title_open" msgid="4353228937663917801">"Բացել այստեղից"</string>
     <string name="title_save" msgid="2433679664882857999">"Պահել այստեղ"</string>
     <string name="menu_create_dir" msgid="5947289605844398389">"Ստեղծել պանակ"</string>
-    <string name="menu_grid" msgid="6878021334497835259">"Ցանցի տեսք"</string>
+    <string name="menu_grid" msgid="6878021334497835259">"Ցանցի տեսքով"</string>
     <string name="menu_list" msgid="7279285939892417279">"Ցուցակի տեսք"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Դասավորել ըստ"</string>
     <string name="menu_search" msgid="3816712084502856974">"Որոնել"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java
index f2bde0e..74170f5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java
@@ -18,7 +18,6 @@
 
 import static com.android.documentsui.Events.isMouseEvent;
 import static com.android.internal.util.Preconditions.checkState;
-import static java.lang.String.format;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -38,6 +37,7 @@
 public class BandSelectManager extends RecyclerView.SimpleOnItemTouchListener {
 
     private static final int NOT_SELECTED = -1;
+    private static final int NOT_SET = -1;
 
     // For debugging purposes.
     private static final String TAG = "BandSelectManager";
@@ -50,14 +50,137 @@
 
     private boolean mIsBandSelectActive = false;
     private Point mOrigin;
+    private Point mPointer;
     private Rect mBounds;
-    // Maintain the last selection made by band, so if bounds shink back, we can unselect
-    // the respective items.
 
-    // Track information
+    // Maintain the last selection made by band, so if bounds shrink back, we can deselect
+    // the respective items.
     private int mCursorDeltaY = 0;
     private int mFirstSelected = NOT_SELECTED;
 
+    // The time at which the current band selection-induced scroll began. If no scroll is in
+    // progress, the value is NOT_SET.
+    private long mScrollStartTime = NOT_SET;
+    private final Runnable mScrollRunnable = new Runnable() {
+        /**
+         * The number of milliseconds of scrolling at which scroll speed continues to increase. At
+         * first, the scroll starts slowly; then, the rate of scrolling increases until it reaches
+         * its maximum value at after this many milliseconds.
+         */
+        private static final long SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
+
+        @Override
+        public void run() {
+            // Compute the number of pixels the pointer's y-coordinate is past the view. Negative
+            // values mean the pointer is at or before the top of the view, and positive values mean
+            // that the pointer is at or after the bottom of the view. Note that one additional
+            // pixel is added here so that the view still scrolls when the pointer is exactly at the
+            // top or bottom.
+            int pixelsPastView = 0;
+            if (mPointer.y <= 0) {
+                pixelsPastView = mPointer.y - 1;
+            } else if (mPointer.y >= mRecyclerView.getHeight() - 1) {
+                pixelsPastView = mPointer.y - mRecyclerView.getHeight() + 1;
+            }
+
+            if (!mIsBandSelectActive || pixelsPastView == 0) {
+                // If band selection is inactive, or if it is active but not at the edge of the
+                // view, no scrolling is necessary.
+                mScrollStartTime = NOT_SET;
+                return;
+            }
+
+            if (mScrollStartTime == NOT_SET) {
+                // If the pointer was previously not at the edge of the view but now is, set the
+                // start time for the scroll.
+                mScrollStartTime = System.currentTimeMillis();
+            }
+
+            // Compute the number of pixels to scroll, and scroll that many pixels.
+            final int numPixels = computeNumPixelsToScroll(
+                    pixelsPastView, System.currentTimeMillis() - mScrollStartTime);
+            mRecyclerView.scrollBy(0, numPixels);
+
+            // Adjust the y-coordinate of the origin the opposite number of pixels so that the
+            // origin remains in the same place relative to the view's items.
+            mOrigin.y -= numPixels;
+            resizeBandSelectRectangle();
+
+            mRecyclerView.removeCallbacks(mScrollRunnable);
+            mRecyclerView.postOnAnimation(this);
+        }
+
+        /**
+         * Computes the number of pixels to scroll based on how far the pointer is past the end of
+         * the view and how long it has been there. Roughly based on ItemTouchHelper's algorithm for
+         * computing the number of pixels to scroll when an item is dragged to the end of a
+         * {@link RecyclerView}.
+         * @param pixelsPastView
+         * @param scrollDuration
+         * @return
+         */
+        private int computeNumPixelsToScroll(int pixelsPastView, long scrollDuration) {
+            final int maxScrollStep = computeMaxScrollStep(mRecyclerView);
+            final int direction = (int) Math.signum(pixelsPastView);
+            final int absPastView = Math.abs(pixelsPastView);
+
+            // Calculate the ratio of how far out of the view the pointer currently resides to the
+            // entire height of the view.
+            final float outOfBoundsRatio = Math.min(
+                    1.0f, (float) absPastView / mRecyclerView.getHeight());
+            // Interpolate this ratio and use it to compute the maximum scroll that should be
+            // possible for this step.
+            final float cappedScrollStep =
+                    direction * maxScrollStep * smoothOutOfBoundsRatio(outOfBoundsRatio);
+
+            // Likewise, calculate the ratio of the time spent in the scroll to the limit.
+            final float timeRatio = Math.min(
+                    1.0f, (float) scrollDuration / SCROLL_ACCELERATION_LIMIT_TIME_MS);
+            // Interpolate this ratio and use it to compute the final number of pixels to scroll.
+            final int numPixels = (int) (cappedScrollStep * smoothTimeRatio(timeRatio));
+
+            // If the final number of pixels to scroll ends up being 0, the view should still scroll
+            // at least one pixel.
+            return numPixels != 0 ? numPixels : direction;
+        }
+
+        /**
+         * Computes the maximum scroll allowed for a given animation frame. Currently, this
+         * defaults to the height of the view, but this could be tweaked if this results in scrolls
+         * that are too fast or too slow.
+         * @param rv
+         * @return
+         */
+        private int computeMaxScrollStep(RecyclerView rv) {
+            return rv.getHeight();
+        }
+
+        /**
+         * Interpolates the given out of bounds ratio on a curve which starts at (0,0) and ends at
+         * (1,1) and quickly approaches 1 near the start of that interval. This ensures that drags
+         * that are at the edge or barely past the edge of the view still cause sufficient
+         * scrolling. The equation y=(x-1)^5+1 is used, but this could also be tweaked if needed.
+         * @param ratio A ratio which is in the range [0, 1].
+         * @return A "smoothed" value, also in the range [0, 1].
+         */
+        private float smoothOutOfBoundsRatio(float ratio) {
+            return (float) Math.pow(ratio - 1.0f, 5) + 1.0f;
+        }
+
+        /**
+         * Interpolates the given time ratio on a curve which starts at (0,0) and ends at (1,1) and
+         * stays close to 0 for most input values except those very close to 1. This ensures that
+         * scrolls start out very slowly but speed up drastically after the scroll has been in
+         * progress close to SCROLL_ACCELERATION_LIMIT_TIME_MS. The equation y=x^5 is used, but this
+         * could also be tweaked if needed.
+         * @param ratio A ratio which is in the range [0, 1].
+         * @return A "smoothed" value, also in the range [0, 1].
+         */
+        private float smoothTimeRatio(float ratio) {
+            return (float) Math.pow(ratio, 5);
+        }
+    };
+
     /**
      * @param recyclerView
      * @param multiSelectManager
@@ -95,41 +218,48 @@
             return;
         }
 
-        Point point = new Point((int) e.getX(), (int) e.getY());
+        mPointer = new Point((int) e.getX(), (int) e.getY());
         if (!mIsBandSelectActive) {
-            startBandSelect(point);
+            startBandSelect();
         }
 
-        resizeBandSelectRectangle(point);
+        scrollViewIfNecessary();
+        resizeBandSelectRectangle();
         selectChildrenCoveredBySelection();
     }
 
     /**
      * Starts band select by adding the drawable to the RecyclerView's overlay.
-     * @param origin The starting point of the selection.
      */
-    private void startBandSelect(Point origin) {
-        if (DEBUG) Log.d(TAG, "Starting band select from (" + origin.x + "," + origin.y + ").");
+    private void startBandSelect() {
+        if (DEBUG) Log.d(TAG, "Starting band select from (" + mPointer.x + "," + mPointer.y + ").");
         mIsBandSelectActive = true;
-        mOrigin = origin;
+        mOrigin = mPointer;
         mRecyclerView.getOverlay().add(mRegionSelectorDrawable);
     }
 
     /**
+     * Scrolls the view if necessary.
+     */
+    private void scrollViewIfNecessary() {
+        mRecyclerView.removeCallbacks(mScrollRunnable);
+        mScrollRunnable.run();
+        mRecyclerView.invalidate();
+    }
+
+    /**
      * Resizes the band select rectangle by using the origin and the current pointer positoin as
      * two opposite corners of the selection.
-     * @param pointerPosition
      */
-    private void resizeBandSelectRectangle(Point pointerPosition) {
-
+    private void resizeBandSelectRectangle() {
         if (mBounds != null) {
-            mCursorDeltaY = pointerPosition.y - mBounds.bottom;
+            mCursorDeltaY = mPointer.y - mBounds.bottom;
         }
 
-        mBounds = new Rect(Math.min(mOrigin.x, pointerPosition.x),
-                Math.min(mOrigin.y, pointerPosition.y),
-                Math.max(mOrigin.x, pointerPosition.x),
-                Math.max(mOrigin.y, pointerPosition.y));
+        mBounds = new Rect(Math.min(mOrigin.x, mPointer.x),
+                Math.min(mOrigin.y, mPointer.y),
+                Math.max(mOrigin.x, mPointer.x),
+                Math.max(mOrigin.y, mPointer.y));
 
         mRegionSelectorDrawable.setBounds(mBounds);
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index a813ce7..9b8d847 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -16,10 +16,13 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
 import static com.android.documentsui.DirectoryFragment.ANIM_UP;
+import static com.android.internal.util.Preconditions.checkArgument;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Intent;
@@ -79,8 +82,9 @@
     private final String mTag;
 
     public abstract State getDisplayState();
-    public abstract void onDocumentPicked(DocumentInfo doc);
+    public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
     public abstract void onDocumentsPicked(List<DocumentInfo> docs);
+
     abstract void onTaskFinished(Uri... uris);
     abstract void onDirectoryChanged(int anim);
     abstract void updateActionBar();
@@ -258,6 +262,17 @@
                 && !root.isDownloads();
     }
 
+    void onDirectoryCreated(DocumentInfo doc) {
+        checkArgument(doc.isDirectory());
+        openDirectory(doc);
+    }
+
+    void openDirectory(DocumentInfo doc) {
+        getDisplayState().stack.push(doc);
+        getDisplayState().stackTouched = true;
+        onCurrentDirectoryChanged(ANIM_DOWN);
+    }
+
     /**
      * Call this when directory changes. Prior to root fragment update
      * the (abstract) directoryChanged method will be called.
@@ -605,7 +620,6 @@
             if (isDestroyed()) return;
             getDisplayState().restored = true;
             onCurrentDirectoryChanged(ANIM_NONE);
-
             onStackRestored(mRestoredStack, mExternal);
         }
     }
@@ -843,4 +857,17 @@
             updateActionBar();
         }
     }
+
+    /**
+     * Interface providing access to current view of documents
+     * even when all documents are not homed to the same parent.
+     */
+    interface DocumentContext {
+        /**
+         * Returns the cursor for the selected document. The cursor can be used to retrieve
+         * details about a document and its siblings.
+         * @return
+         */
+        Cursor getCursor();
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 1b6d642..f927595 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -146,7 +146,7 @@
         protected void onPostExecute(DocumentInfo result) {
             if (result != null) {
                 // Navigate into newly created child
-                mActivity.onDocumentPicked(result);
+                mActivity.onDirectoryCreated(result);
             } else {
                 Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show();
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 9468cfd..7e6ec8b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -89,6 +89,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.documentsui.BaseActivity.DocumentContext;
 import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.MultiSelectManager.Selection;
 import com.android.documentsui.ProviderExecutor.Preemptable;
@@ -457,7 +458,7 @@
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
         if (isDocumentEnabled(docMimeType, docFlags)) {
             final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
-            ((BaseActivity) getActivity()).onDocumentPicked(doc);
+            ((BaseActivity) getActivity()).onDocumentPicked(doc, mAdapter);
             mSelectionManager.clearSelection();
             return true;
         }
@@ -949,7 +950,8 @@
         }
     }
 
-    private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
+    private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder>
+            implements DocumentContext {
 
         private final Context mContext;
         private final LayoutInflater mInflater;
@@ -1213,6 +1215,14 @@
             }
         }
 
+        @Override
+        public Cursor getCursor() {
+            if (Looper.myLooper() != Looper.getMainLooper()) {
+                throw new IllegalStateException("Can't call getCursor from non-main thread.");
+            }
+            return mCursor;
+        }
+
         private Cursor getItem(int position) {
             if (position < mCursorCount) {
                 mCursor.moveToPosition(position);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 272700b..2de7fc4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -26,12 +26,8 @@
 import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.DirectoryFragment.ANIM_UP;
+import static com.android.internal.util.Preconditions.checkArgument;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -608,12 +604,10 @@
     }
 
     @Override
-    public void onDocumentPicked(DocumentInfo doc) {
+    public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
         final FragmentManager fm = getFragmentManager();
         if (doc.isDirectory()) {
-            mState.stack.push(doc);
-            mState.stackTouched = true;
-            onCurrentDirectoryChanged(ANIM_DOWN);
+            openDirectory(doc);
         } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
             // Explicit file picked, return
             new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor());
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
new file mode 100644
index 0000000..878c4c2
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 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.documentsui;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.annotation.Nullable;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import com.android.documentsui.BaseActivity.DocumentContext;
+import com.android.documentsui.model.DocumentInfo;
+
+/**
+ * Provides support for gather a list of quick-viewable files into a quick view intent.
+ */
+final class QuickViewIntentBuilder {
+
+    private static final String TAG = "QvIntentBuilder";
+    private static final boolean DEBUG = false;
+
+    private final DocumentInfo mDocument;
+    private final DocumentContext mContext;
+
+    public ClipData mClipData;
+    public int mDocumentLocation;
+    private PackageManager mPkgManager;
+
+    public QuickViewIntentBuilder(
+            PackageManager pkgManager, DocumentInfo doc, DocumentContext context) {
+        mPkgManager = pkgManager;
+        mDocument = doc;
+        mContext = context;
+    }
+
+    /**
+     * Builds the intent for quick viewing. Short circuits building if a handler cannot
+     * be resolved; in this case {@code null} is returned.
+     */
+    @Nullable Intent build() {
+        if (DEBUG) Log.d(TAG, "Preparing intent for doc:" + mDocument.documentId);
+
+        Intent intent = new Intent(Intent.ACTION_QUICK_VIEW);
+        intent.setDataAndType(mDocument.derivedUri, mDocument.mimeType);
+
+        // Try to resolve the intent. If a matching app isn't installed, it won't resolve.
+        ComponentName handler = intent.resolveActivity(mPkgManager);
+        if (handler == null) {
+            return null;
+        }
+
+        Cursor cursor = mContext.getCursor();
+        for (int i = 0; i < cursor.getCount(); i++) {
+            onNextItem(i, cursor);
+        }
+
+        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        intent.putExtra(Intent.EXTRA_INDEX, mDocumentLocation);
+        intent.setClipData(mClipData);
+
+        return intent;
+    }
+
+    private void onNextItem(int index, Cursor cursor) {
+        cursor.moveToPosition(index);
+
+        String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+            return;
+        }
+
+        String id = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+        String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+        Uri uri = DocumentsContract.buildDocumentUri(authority, id);
+        if (DEBUG) Log.d(TAG, "Including file[" + id + "] @ " + uri);
+
+        if (id.equals(mDocument.documentId)) {
+            if (DEBUG) Log.d(TAG, "Found starting point for QV. " + index);
+            mDocumentLocation = index;
+        }
+
+        ClipData.Item item = new ClipData.Item(uri);
+        if (mClipData == null) {
+            mClipData = new ClipData(
+                    "URIs", new String[]{ClipDescription.MIMETYPE_TEXT_URILIST}, item);
+        } else {
+            mClipData.addItem(item);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
index 5f40dab..1ca277d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
@@ -25,7 +25,6 @@
 import android.app.FragmentManager;
 import android.content.ActivityNotFoundException;
 import android.content.ClipData;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -61,6 +60,7 @@
 public class StandaloneActivity extends BaseActivity {
 
     public static final String TAG = "StandaloneFileManagement";
+    static final boolean DEBUG = false;
 
     private Toolbar mToolbar;
     private Spinner mToolbarStack;
@@ -284,31 +284,41 @@
     }
 
     @Override
-    public void onDocumentPicked(DocumentInfo doc) {
-        if (doc.isDirectory()) {
-            openFolder(doc);
-        } else {
-            openDocument(doc);
-        }
+    public void onDocumentsPicked(List<DocumentInfo> docs) {
+        throw new UnsupportedOperationException();
     }
 
-    private void openFolder(DocumentInfo doc) {
-        mState.stack.push(doc);
-        mState.stackTouched = true;
-        onCurrentDirectoryChanged(ANIM_DOWN);
+    @Override
+    public void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings) {
+        if (doc.isDirectory()) {
+            openDirectory(doc);
+        } else {
+            openDocument(doc, siblings);
+        }
     }
 
     /**
      * Launches an intent to view the specified document.
      */
-    private void openDocument(DocumentInfo doc) {
-        Intent intent = getQuickViewIntent(doc);
+    private void openDocument(DocumentInfo doc, @Nullable DocumentContext siblings) {
+        Intent intent = null;
+        if (siblings != null) {
+            QuickViewIntentBuilder builder =
+                    new QuickViewIntentBuilder(getPackageManager(), doc, siblings);
+            intent = builder.build();
+        }
+
+        // fallback to traditional VIEW action...
         if (intent == null) {
             intent = new Intent(Intent.ACTION_VIEW);
             intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             intent.setData(doc.derivedUri);
         }
 
+        if (DEBUG && intent.getClipData() != null) {
+            Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData());
+        }
+
         try {
             startActivity(intent);
         } catch (ActivityNotFoundException ex2) {
@@ -316,24 +326,6 @@
         }
     }
 
-    private @Nullable Intent getQuickViewIntent(DocumentInfo doc) {
-        Intent intent = new Intent(Intent.ACTION_QUICK_VIEW);
-        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        intent.setData(doc.derivedUri);
-
-        ComponentName handler = intent.resolveActivity(getPackageManager());
-        if (handler != null) {
-            return intent;
-        }
-
-        return null;
-    }
-
-    @Override
-    public void onDocumentsPicked(List<DocumentInfo> docs) {
-        // TODO
-    }
-
     @Override
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
         DirectoryFragment dir;
diff --git a/packages/ExternalStorageProvider/res/values-fa/strings.xml b/packages/ExternalStorageProvider/res/values-fa/strings.xml
index 8471fc7..9ae8a47 100644
--- a/packages/ExternalStorageProvider/res/values-fa/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7123375275748530234">"فضای ذخیره خارجی"</string>
+    <string name="app_label" msgid="7123375275748530234">"حافظه خارجی"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"حافظهٔ داخلی"</string>
     <string name="root_documents" msgid="4051252304075469250">"اسناد"</string>
 </resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5183c35..55d85206 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -557,6 +557,7 @@
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
 
+        @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             if (DEBUG) Log.d(TAG, "received broadcast " + action);
@@ -610,6 +611,7 @@
 
     private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
 
+        @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {
@@ -724,6 +726,7 @@
             return new SimData(state, slotId, subId);
         }
 
+        @Override
         public String toString() {
             return "SimData{state=" + simState + ",slotId=" + slotId + ",subId=" + subId + "}";
         }
@@ -939,7 +942,9 @@
     }
 
     private boolean shouldListenForFingerprint() {
-        return mKeyguardIsVisible && !mSwitchingUser;
+        return mKeyguardIsVisible && !mSwitchingUser &&
+                mTrustManager.hasUserAuthenticatedSinceBoot(
+                        ActivityManager.getCurrentUser());
     }
 
     private void startListeningForFingerprint() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
index 5222826..f6e4276 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
@@ -67,6 +67,10 @@
         this.mThumbSize = thumbSize;
     }
 
+    int getSize() {
+        return mSize;
+    }
+
     String getMimeType() {
         // TODO: Add complete list of mime types.
         switch (mFormat) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index fab5125..c9db29e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -17,8 +17,10 @@
 package com.android.mtp;
 
 import android.content.ContentResolver;
+import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.graphics.Point;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 import android.provider.DocumentsContract;
@@ -53,6 +55,7 @@
 
     private MtpManager mMtpManager;
     private ContentResolver mResolver;
+    private PipeManager mPipeManager;
 
     /**
      * Provides singleton instance to MtpDocumentsService.
@@ -66,6 +69,8 @@
         sSingleton = this;
         mMtpManager = new MtpManager(getContext());
         mResolver = getContext().getContentResolver();
+        mPipeManager = new PipeManager();
+
         return true;
     }
 
@@ -156,9 +161,51 @@
     }
 
     @Override
-    public ParcelFileDescriptor openDocument(String documentId, String mode,
+    public ParcelFileDescriptor openDocument(
+            String documentId, String mode, CancellationSignal signal)
+                    throws FileNotFoundException {
+        if (!"r".equals(mode) && !"w".equals(mode)) {
+            // TODO: Support seekable file.
+            throw new UnsupportedOperationException("The provider does not support seekable file.");
+        }
+        final Identifier identifier = Identifier.createFromDocumentId(documentId);
+        try {
+            final MtpDocument document =
+                    mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
+            return mPipeManager.readDocument(mMtpManager, identifier);
+        } catch (IOException error) {
+            throw new FileNotFoundException(error.getMessage());
+        }
+    }
+
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(
+            String documentId,
+            Point sizeHint,
             CancellationSignal signal) throws FileNotFoundException {
-        throw new FileNotFoundException();
+        final Identifier identifier = Identifier.createFromDocumentId(documentId);
+        try {
+            return new AssetFileDescriptor(
+                    mPipeManager.readThumbnail(mMtpManager, identifier),
+                    0,
+                    AssetFileDescriptor.UNKNOWN_LENGTH);
+        } catch (IOException error) {
+            throw new FileNotFoundException(error.getMessage());
+        }
+    }
+
+    @Override
+    public void deleteDocument(String documentId) throws FileNotFoundException {
+        try {
+            final Identifier identifier = Identifier.createFromDocumentId(documentId);
+            final int parentHandle =
+                    mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
+            mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
+            notifyChildDocumentsChange(new Identifier(
+                    identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
+        } catch (IOException error) {
+            throw new FileNotFoundException(error.getMessage());
+        }
     }
 
     void openDevice(int deviceId) throws IOException {
@@ -192,7 +239,12 @@
 
     private void notifyRootsChange() {
         mResolver.notifyChange(
-                DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY),
+                DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY), null, false);
+    }
+
+    private void notifyChildDocumentsChange(String parentDocumentId) {
+        mResolver.notifyChange(
+                DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId),
                 null,
                 false);
     }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index e34312c..d4ee668 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -21,8 +21,10 @@
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
 import android.mtp.MtpDevice;
+import android.os.ParcelFileDescriptor;
 import android.util.SparseArray;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 
 /**
@@ -103,6 +105,38 @@
         return new MtpDocument(device.getObjectInfo(objectHandle));
     }
 
+    synchronized byte[] getObject(int deviceId, int objectHandle, int expectedSize)
+            throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        return device.getObject(objectHandle, expectedSize);
+    }
+
+    synchronized byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        return device.getThumbnail(objectHandle);
+    }
+
+    synchronized void deleteDocument(int deviceId, int objectHandle) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        if (!device.deleteObject(objectHandle)) {
+            throw new IOException("Failed to delete document");
+        }
+    }
+
+    synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        final int result = (int) device.getParent(objectHandle);
+        if (result < 0) {
+            throw new FileNotFoundException("Not found parent object");
+        }
+        return result;
+    }
+
+    synchronized void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
+            throws IOException {
+        throw new UnsupportedOperationException("Importing files is not supported.");
+    }
+
     private MtpDevice getDevice(int deviceId) throws IOException {
         final MtpDevice device = mDevices.get(deviceId);
         if (device == null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
new file mode 100644
index 0000000..7f498f5
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 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.mtp;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+class PipeManager {
+    final ExecutorService mExecutor;
+
+    PipeManager() {
+        this(Executors.newCachedThreadPool());
+    }
+
+    PipeManager(ExecutorService executor) {
+        this.mExecutor = executor;
+    }
+
+    ParcelFileDescriptor readDocument(MtpManager model, Identifier identifier) throws IOException {
+        final Task task = new ImportFileTask(model, identifier);
+        mExecutor.execute(task);
+        return task.getReadingFileDescriptor();
+    }
+
+    ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
+        final Task task = new GetThumbnailTask(model, identifier);
+        mExecutor.execute(task);
+        return task.getReadingFileDescriptor();
+    }
+
+    private static abstract class Task implements Runnable {
+        protected final MtpManager mModel;
+        protected final Identifier mIdentifier;
+        protected final ParcelFileDescriptor[] mDescriptors;
+
+        Task(MtpManager model, Identifier identifier) throws IOException {
+            mModel = model;
+            mIdentifier = identifier;
+            mDescriptors = ParcelFileDescriptor.createReliablePipe();
+        }
+
+        ParcelFileDescriptor getReadingFileDescriptor() {
+            return mDescriptors[0];
+        }
+    }
+
+    private static class ImportFileTask extends Task {
+        ImportFileTask(MtpManager model, Identifier identifier) throws IOException {
+            super(model, identifier);
+        }
+
+        @Override
+        public void run() {
+            try {
+                mModel.importFile(
+                        mIdentifier.mDeviceId, mIdentifier.mObjectHandle, mDescriptors[1]);
+                mDescriptors[1].close();
+            } catch (IOException error) {
+                try {
+                    mDescriptors[1].closeWithError("Failed to stream a file.");
+                } catch (IOException closeError) {
+                    Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
+                }
+            }
+        }
+    }
+
+    private static class GetThumbnailTask extends Task {
+        GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
+            super(model, identifier);
+        }
+
+        @Override
+        public void run() {
+            try {
+                try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                        new ParcelFileDescriptor.AutoCloseOutputStream(mDescriptors[1])) {
+                    try {
+                        stream.write(mModel.getThumbnail(
+                                mIdentifier.mDeviceId, mIdentifier.mObjectHandle));
+                    } catch (IOException error) {
+                        mDescriptors[1].closeWithError("Failed to stream a thumbnail.");
+                    }
+                }
+            } catch (IOException closeError) {
+                Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
+            }
+        }
+    }
+
+    void close() {
+        mExecutor.shutdown();
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 2a612cb..3fad63f 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -25,8 +25,11 @@
 import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 
 @SmallTest
 public class MtpDocumentsProviderTest extends AndroidTestCase {
@@ -43,14 +46,16 @@
     }
 
     public void testOpenAndCloseDevice() throws Exception {
+        final Uri uri = DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
+
         mMtpManager.addValidDevice(0);
-        assertEquals(0, mResolver.changeCount);
+        assertEquals(0, mResolver.getChangeCount(uri));
 
         mProvider.openDevice(0);
-        assertEquals(1, mResolver.changeCount);
+        assertEquals(1, mResolver.getChangeCount(uri));
 
         mProvider.closeDevice(0);
-        assertEquals(2, mResolver.changeCount);
+        assertEquals(2, mResolver.getChangeCount(uri));
 
         int exceptionCounter = 0;
         try {
@@ -58,27 +63,29 @@
         } catch (IOException error) {
             exceptionCounter++;
         }
-        assertEquals(2, mResolver.changeCount);
+        assertEquals(2, mResolver.getChangeCount(uri));
         try {
             mProvider.closeDevice(1);
         } catch (IOException error) {
             exceptionCounter++;
         }
-        assertEquals(2, mResolver.changeCount);
+        assertEquals(2, mResolver.getChangeCount(uri));
         assertEquals(2, exceptionCounter);
     }
 
     public void testCloseAllDevices() throws IOException {
+        final Uri uri = DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
+
         mMtpManager.addValidDevice(0);
 
         mProvider.closeAllDevices();
-        assertEquals(0, mResolver.changeCount);
+        assertEquals(0, mResolver.getChangeCount(uri));
 
         mProvider.openDevice(0);
-        assertEquals(1, mResolver.changeCount);
+        assertEquals(1, mResolver.getChangeCount(uri));
 
         mProvider.closeAllDevices();
-        assertEquals(2, mResolver.changeCount);
+        assertEquals(2, mResolver.getChangeCount(uri));
     }
 
     public void testQueryRoots() throws Exception {
@@ -210,12 +217,48 @@
         assertEquals(3072, cursor.getInt(5));
     }
 
+    public void testDeleteDocument() throws FileNotFoundException {
+        mMtpManager.setDocument(0, 1, new MtpDocument(
+                1 /* object handle */,
+                0x3801 /* JPEG */,
+                "image.jpg" /* display name */,
+                new Date(1422716400000L) /* modified date */,
+                1024 * 1024 * 5 /* file size */,
+                1024 * 50 /* thumbnail size */));
+        mMtpManager.setParent(0, 1, 2);
+        mProvider.deleteDocument("0_0_1");
+        assertEquals(1, mResolver.getChangeCount(
+                DocumentsContract.buildChildDocumentsUri(
+                        MtpDocumentsProvider.AUTHORITY, "0_0_2")));
+    }
+
+    public void testDeleteDocument_error() throws FileNotFoundException {
+        mMtpManager.setParent(0, 1, 2);
+        try {
+            mProvider.deleteDocument("0_0_1");
+            fail();
+        } catch (Throwable e) {
+            assertTrue(e instanceof IOException);
+        }
+        assertEquals(0, mResolver.getChangeCount(
+                DocumentsContract.buildChildDocumentsUri(
+                        MtpDocumentsProvider.AUTHORITY, "0_0_2")));
+    }
+
     private static class ContentResolver extends MockContentResolver {
-        int changeCount = 0;
+        final Map<Uri, Integer> mChangeCounts = new HashMap<Uri, Integer>();
 
         @Override
         public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
-            changeCount++;
+            mChangeCounts.put(uri, getChangeCount(uri) + 1);
+        }
+
+        int getChangeCount(Uri uri) {
+            if (mChangeCounts.containsKey(uri)) {
+                return mChangeCounts.get(uri);
+            } else {
+                return 0;
+            }
         }
     }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
new file mode 100644
index 0000000..35918e1
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 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.mtp;
+
+import android.os.ParcelFileDescriptor;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+public class PipeManagerTest extends AndroidTestCase {
+    private static final byte[] HELLO_BYTES = new byte[] { 'h', 'e', 'l', 'l', 'o' };
+
+    private TestMtpManager mtpManager;
+    private ExecutorService executor;
+    private PipeManager pipeManager;
+
+    @Override
+    public void setUp() {
+        mtpManager = new TestMtpManager(getContext());
+        executor = Executors.newSingleThreadExecutor();
+        pipeManager = new PipeManager(executor);
+    }
+
+    public void testReadDocument_basic() throws Exception {
+        mtpManager.setImportFileBytes(0, 1, HELLO_BYTES);
+        final ParcelFileDescriptor descriptor = pipeManager.readDocument(
+                mtpManager, new Identifier(0, 0, 1));
+        assertDescriptor(descriptor, HELLO_BYTES);
+    }
+
+    public void testReadDocument_error() throws Exception {
+        final ParcelFileDescriptor descriptor =
+                pipeManager.readDocument(mtpManager, new Identifier(0, 0, 1));
+        assertDescriptorError(descriptor);
+    }
+
+    public void testReadThumbnail_basic() throws Exception {
+        mtpManager.setThumbnail(0, 1, HELLO_BYTES);
+        final ParcelFileDescriptor descriptor = pipeManager.readThumbnail(
+                mtpManager, new Identifier(0, 0, 1));
+        assertDescriptor(descriptor, HELLO_BYTES);
+    }
+
+    public void testReadThumbnail_error() throws Exception {
+        final ParcelFileDescriptor descriptor =
+                pipeManager.readThumbnail(mtpManager, new Identifier(0, 0, 1));
+        assertDescriptorError(descriptor);
+    }
+
+    private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes)
+            throws IOException, InterruptedException {
+        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
+                new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
+            byte[] results = new byte[100];
+            assertEquals(expectedBytes.length, stream.read(results));
+            for (int i = 0; i < expectedBytes.length; i++) {
+                assertEquals(expectedBytes[i], results[i]);
+            }
+        }
+    }
+
+    private void assertDescriptorError(ParcelFileDescriptor descriptor)
+            throws InterruptedException {
+        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+        try {
+            descriptor.checkError();
+            fail();
+        } catch (Throwable error) {
+            assertTrue(error instanceof IOException);
+        }
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 08ceb293..725b765 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -17,6 +17,7 @@
 package com.android.mtp;
 
 import android.content.Context;
+import android.os.ParcelFileDescriptor;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -35,6 +36,9 @@
     private final Set<Integer> mOpenedDevices = new TreeSet<Integer>();
     private final Map<Integer, MtpRoot[]> mRoots = new HashMap<Integer, MtpRoot[]>();
     private final Map<String, MtpDocument> mDocuments = new HashMap<String, MtpDocument>();
+    private final Map<String, byte[]> mThumbnailBytes = new HashMap<String, byte[]>();
+    private final Map<String, Integer> mParents = new HashMap<String, Integer>();
+    private final Map<String, byte[]> mImportFileBytes = new HashMap<String, byte[]>();
 
     TestMtpManager(Context context) {
         super(context);
@@ -52,6 +56,18 @@
         mDocuments.put(pack(deviceId, objectHandle), document);
     }
 
+    void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
+        mImportFileBytes.put(pack(deviceId, objectHandle), bytes);
+    }
+
+    void setThumbnail(int deviceId, int objectHandle, byte[] bytes) {
+        mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
+    }
+
+    void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
+        mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
+    }
+
     @Override
     void openDevice(int deviceId) throws IOException {
         if (!mValidDevices.contains(deviceId) || mOpenedDevices.contains(deviceId)) {
@@ -83,6 +99,49 @@
     }
 
     @Override
+    void importFile(int deviceId, int storageId, ParcelFileDescriptor target) throws IOException {
+        final String key = pack(deviceId, storageId);
+        if (mImportFileBytes.containsKey(key)) {
+            try (final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
+                    new ParcelFileDescriptor.AutoCloseOutputStream(target)) {
+                outputStream.write(mImportFileBytes.get(key));
+            }
+        } else {
+            throw new IOException("importFile error: " + key);
+        }
+    }
+
+    @Override
+    byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
+        final String key = pack(deviceId, objectHandle);
+        if (mThumbnailBytes.containsKey(key)) {
+            return mThumbnailBytes.get(key);
+        } else {
+            throw new IOException("getThumbnail error: " + key);
+        }
+    }
+
+    @Override
+    void deleteDocument(int deviceId, int objectHandle) throws IOException {
+        final String key = pack(deviceId, objectHandle);
+        if (mDocuments.containsKey(key)) {
+            mDocuments.remove(key);
+        } else {
+            throw new IOException();
+        }
+    }
+
+    @Override
+    synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+        final String key = pack(deviceId, objectHandle);
+        if (mParents.containsKey(key)) {
+            return mParents.get(key);
+        } else {
+            throw new IOException();
+        }
+    }
+
+    @Override
     int[] getOpenedDeviceIds() {
         int i = 0;
         final int[] result = new int[mOpenedDevices.size()];
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 58e5e29a..096a5c4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -23,7 +23,7 @@
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.SystemProperties;
-import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 
 public class TetherUtil {
@@ -99,8 +99,9 @@
     public static boolean isTetheringSupported(Context context) {
         final ConnectivityManager cm =
                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        final boolean isSecondaryUser = ActivityManager.getCurrentUser() != UserHandle.USER_OWNER;
-        return !isSecondaryUser && cm.isTetheringSupported();
+        final boolean isAdminUser =
+                UserManager.get(context).isUserAdmin(ActivityManager.getCurrentUser());
+        return isAdminUser && cm.isTetheringSupported();
     }
 
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 9eb7d0e..c9a5f8f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageStats;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
@@ -88,7 +89,7 @@
     final PackageManager mPm;
     final IPackageManager mIpm;
     final UserManager mUm;
-    final int mOwnerRetrieveFlags;
+    final int mAdminRetrieveFlags;
     final int mRetrieveFlags;
     PackageIntentReceiver mPackageIntentReceiver;
 
@@ -131,7 +132,7 @@
         mBackgroundHandler = new BackgroundHandler(mThread.getLooper());
 
         // Only the owner can see all apps.
-        mOwnerRetrieveFlags = PackageManager.GET_UNINSTALLED_PACKAGES |
+        mAdminRetrieveFlags = PackageManager.GET_UNINSTALLED_PACKAGES |
                 PackageManager.GET_DISABLED_COMPONENTS |
                 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS;
         mRetrieveFlags = PackageManager.GET_DISABLED_COMPONENTS |
@@ -181,17 +182,17 @@
             mPackageIntentReceiver.registerReceiver();
         }
         mApplications = new ArrayList<ApplicationInfo>();
-        for (UserHandle user : mUm.getUserProfiles()) {
+        for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
             try {
                 // If this user is new, it needs a map created.
-                if (mEntriesMap.indexOfKey(user.getIdentifier()) < 0) {
-                    mEntriesMap.put(user.getIdentifier(), new HashMap<String, AppEntry>());
+                if (mEntriesMap.indexOfKey(user.id) < 0) {
+                    mEntriesMap.put(user.id, new HashMap<String, AppEntry>());
                 }
                 @SuppressWarnings("unchecked")
                 ParceledListSlice<ApplicationInfo> list =
                         mIpm.getInstalledApplications(
-                                user.isOwner() ? mOwnerRetrieveFlags : mRetrieveFlags,
-                                user.getIdentifier());
+                                user.isAdmin() ? mAdminRetrieveFlags : mRetrieveFlags,
+                                user.id);
                 mApplications.addAll(list.getList());
             } catch (RemoteException e) {
             }
@@ -363,7 +364,7 @@
                     return;
                 }
                 ApplicationInfo info = mIpm.getApplicationInfo(pkgName,
-                        userId == UserHandle.USER_OWNER ? mOwnerRetrieveFlags : mRetrieveFlags,
+                        mUm.isUserAdmin(userId) ? mAdminRetrieveFlags : mRetrieveFlags,
                         userId);
                 if (info == null) {
                     return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 5d3d120..9790e64 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -314,7 +314,7 @@
                         } else {
                             Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
                             mContext.bindServiceAsUser(service, mDefContainerConn,
-                                    Context.BIND_AUTO_CREATE, UserHandle.OWNER);
+                                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
                         }
                     }
                     break;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 348d0ec..632a867 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -151,7 +151,7 @@
                 mScanResultCache.put(result.BSSID, result);
             }
         }
-        update(mInfo, mNetworkInfo);
+        update(mConfig, mInfo, mNetworkInfo);
         mRssi = getRssi();
         mSeen = getSeen();
     }
@@ -629,11 +629,18 @@
         return mConfig != null && mConfig.isPasspoint();
     }
 
-    /** Return whether the given {@link WifiInfo} is for this access point. */
-    private boolean isInfoForThisAccessPoint(WifiInfo info) {
+    /**
+     * Return whether the given {@link WifiInfo} is for this access point.
+     * If the current AP does not have a network Id then the config is used to
+     * match based on SSID and security.
+     */
+    private boolean isInfoForThisAccessPoint(WifiConfiguration config, WifiInfo info) {
         if (isPasspoint() == false && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
             return networkId == info.getNetworkId();
-        } else {
+        } else if (config != null) {
+            return matches(config);
+        }
+        else {
             // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
             // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
             // TODO: Handle hex string SSIDs.
@@ -705,7 +712,7 @@
     }
 
     boolean update(ScanResult result) {
-        if (ssid.equals(result.SSID) && security == getSecurity(result)) {
+        if (matches(result)) {
             /* Update the LRU timestamp, if BSSID exists */
             mScanResultCache.get(result.BSSID);
 
@@ -735,9 +742,9 @@
         return false;
     }
 
-    boolean update(WifiInfo info, NetworkInfo networkInfo) {
+    boolean update(WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
         boolean reorder = false;
-        if (info != null && isInfoForThisAccessPoint(info)) {
+        if (info != null && isInfoForThisAccessPoint(config, info)) {
             reorder = (mInfo == null);
             mRssi = info.getRssi();
             mInfo = info;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 33f993e..c28288e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -281,6 +281,19 @@
         return mScanResultCache.values();
     }
 
+    private WifiConfiguration getWifiConfigurationForNetworkId(int networkId) {
+        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        if (configs != null) {
+            for (WifiConfiguration config : configs) {
+                if (mLastInfo != null && networkId == config.networkId &&
+                        !(config.selfAdded && config.numAssociation == 0)) {
+                    return config;
+                }
+            }
+        }
+        return null;
+    }
+
     private void updateAccessPoints() {
         // Swap the current access points into a cached list.
         List<AccessPoint> cachedAccessPoints = getAccessPoints();
@@ -295,21 +308,21 @@
          * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
         Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
         WifiConfiguration connectionConfig = null;
+        if (mLastInfo != null) {
+            connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId());
+        }
 
         final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
         if (configs != null) {
             mSavedNetworksExist = configs.size() != 0;
             for (WifiConfiguration config : configs) {
-                if (mLastInfo != null && mLastInfo.getNetworkId() == config.networkId) {
-                    connectionConfig = config;
-                }
                 if (config.selfAdded && config.numAssociation == 0) {
                     continue;
                 }
                 AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
                 if (mLastInfo != null && mLastNetworkInfo != null) {
                     if (config.isPasspoint() == false) {
-                        accessPoint.update(mLastInfo, mLastNetworkInfo);
+                        accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                     }
                 }
                 if (mIncludeSaved) {
@@ -346,7 +359,7 @@
                 if (!found && mIncludeScans) {
                     AccessPoint accessPoint = getCachedOrCreate(result, cachedAccessPoints);
                     if (mLastInfo != null && mLastNetworkInfo != null) {
-                        accessPoint.update(mLastInfo, mLastNetworkInfo);
+                        accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                     }
 
                     if (result.isPasspointNetwork()) {
@@ -437,9 +450,14 @@
             mLastNetworkInfo = networkInfo;
         }
 
+        WifiConfiguration connectionConfig = null;
+        if (mLastInfo != null) {
+            connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId());
+        }
+
         boolean reorder = false;
         for (int i = mAccessPoints.size() - 1; i >= 0; --i) {
-            if (mAccessPoints.get(i).update(mLastInfo, mLastNetworkInfo)) {
+            if (mAccessPoints.get(i).update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
                 reorder = true;
             }
         }
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 477d9d7..2168e8b 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -63,4 +63,4 @@
         android:background="@drawable/recents_button_bg"
         android:visibility="invisible"
         android:src="@drawable/recents_dismiss_light" />
-</com.android.systemui.recents.views.TaskViewHeader>
\ No newline at end of file
+</com.android.systemui.recents.views.TaskViewHeader>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2de2fb2..eceee64 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -431,5 +431,5 @@
     <string name="tuner_toast" msgid="603429811084428439">"Félicitations! System UI Tuner a bien été ajouté aux paramètres."</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Supprimer des paramètres"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Supprimer « System UI Tuner » des paramètres et arrêter d\'utiliser toutes ses fonctionnalités?"</string>
-    <string name="activity_not_found" msgid="348423244327799974">"L\'application est pas installée sur votre appareil"</string>
+    <string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 27305d8..cb8cbcb 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -429,5 +429,5 @@
     <string name="tuner_toast" msgid="603429811084428439">"Grattis! Inställningar för systemgränssnitt har lagts till i inställningarna."</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Ta bort från inställningarna"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vill du ta bort inställningar för systemgränssnitt från inställningarna och sluta använda alla tillhörande funktioner?"</string>
-    <string name="activity_not_found" msgid="348423244327799974">"Appen är inte installerad på enheten."</string>
+    <string name="activity_not_found" msgid="348423244327799974">"Appen är inte installerad på enheten"</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 714b0a8..ec19e5a 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -47,7 +47,7 @@
 
     public void register(Context context) {
         IntentFilter f = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        context.registerReceiverAsUser(this, UserHandle.OWNER,
+        context.registerReceiverAsUser(this, UserHandle.SYSTEM,
                 f, null /* permission */, null /* scheduler */);
     }
 
@@ -121,8 +121,8 @@
 
         try {
             if (newGuest == null) {
-                Log.e(TAG, "Could not create new guest, switching back to owner");
-                ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
+                Log.e(TAG, "Could not create new guest, switching back to system user");
+                ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM);
                 userManager.removeUser(currentUser.id);
                 WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
                 return;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f0154a7..ae6ce53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -340,7 +340,7 @@
         @Override
         public void onUserSwitchComplete(int userId) {
             mSwitchingUser = false;
-            if (userId != UserHandle.USER_OWNER) {
+            if (userId != UserHandle.USER_SYSTEM) {
                 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
                 if (info != null && info.isGuest()) {
                     // If we just switched to a guest, try to dismiss keyguard.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 8c2ac88..0cfa7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -20,7 +20,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -62,15 +61,15 @@
 import java.util.ArrayList;
 
 /**
- * Annotation for a method that is only called from the primary user's SystemUI process and will be
+ * Annotation for a method that is only called from the system user's SystemUI process and will be
  * proxied to the current user.
  */
-@interface ProxyFromPrimaryToCurrentUser {}
+@interface ProxyFromSystemToCurrentUser {}
 /**
  * Annotation for a method that may be called from any user's SystemUI process and will be proxied
- * to the primary user.
+ * to the system user.
  */
-@interface ProxyFromAnyToPrimaryUser {}
+@interface ProxyFromAnyToSystemUser {}
 
 /** A proxy implementation for the recents component */
 public class Recents extends SystemUI
@@ -225,7 +224,7 @@
     }
 
     /** Initializes the Recents. */
-    @ProxyFromPrimaryToCurrentUser
+    @ProxyFromSystemToCurrentUser
     @Override
     public void start() {
         if (sInstance == null) {
@@ -245,7 +244,7 @@
         // Only the owner has the callback to update the SysUI visibility flags, so all non-owner
         // instances of AlternateRecentsComponent needs to notify the owner when the visibility
         // changes.
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
+        if (mSystemServicesProxy.isForegroundUserSystem()) {
             mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
             IntentFilter filter = new IntentFilter();
             filter.addAction(Recents.ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
@@ -278,10 +277,10 @@
     }
 
     /** Shows the Recents. */
-    @ProxyFromPrimaryToCurrentUser
+    @ProxyFromSystemToCurrentUser
     @Override
     public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
+        if (mSystemServicesProxy.isForegroundUserSystem()) {
             showRecentsInternal(triggeredFromAltTab);
         } else {
             Intent intent = createLocalBroadcastIntent(mContext,
@@ -302,10 +301,10 @@
     }
 
     /** Hides the Recents. */
-    @ProxyFromPrimaryToCurrentUser
+    @ProxyFromSystemToCurrentUser
     @Override
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
+        if (mSystemServicesProxy.isForegroundUserSystem()) {
             hideRecentsInternal(triggeredFromAltTab, triggeredFromHomeKey);
         } else {
             Intent intent = createLocalBroadcastIntent(mContext,
@@ -328,10 +327,10 @@
     }
 
     /** Toggles the Recents activity. */
-    @ProxyFromPrimaryToCurrentUser
+    @ProxyFromSystemToCurrentUser
     @Override
     public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
+        if (mSystemServicesProxy.isForegroundUserSystem()) {
             toggleRecentsInternal();
         } else {
             Intent intent = createLocalBroadcastIntent(mContext,
@@ -351,10 +350,10 @@
     }
 
     /** Preloads info for the Recents activity. */
-    @ProxyFromPrimaryToCurrentUser
+    @ProxyFromSystemToCurrentUser
     @Override
     public void preloadRecents() {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
+        if (mSystemServicesProxy.isForegroundUserSystem()) {
             preloadRecentsInternal();
         } else {
             Intent intent = createLocalBroadcastIntent(mContext,
@@ -483,9 +482,9 @@
     }
 
     /** Updates on configuration change. */
-    @ProxyFromPrimaryToCurrentUser
+    @ProxyFromSystemToCurrentUser
     public void onConfigurationChanged(Configuration newConfig) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
+        if (mSystemServicesProxy.isForegroundUserSystem()) {
             configurationChanged();
         } else {
             Intent intent = createLocalBroadcastIntent(mContext,
@@ -849,16 +848,16 @@
     }
 
     /** Notifies the callbacks that the visibility of Recents has changed. */
-    @ProxyFromAnyToPrimaryUser
+    @ProxyFromAnyToSystemUser
     public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp,
             boolean visible) {
-        if (ssp.isForegroundUserOwner()) {
+        if (ssp.isForegroundUserSystem()) {
             visibilityChanged(visible);
         } else {
             Intent intent = createLocalBroadcastIntent(context,
                     ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
             intent.putExtra(EXTRA_RECENTS_VISIBILITY, visible);
-            context.sendBroadcastAsUser(intent, UserHandle.OWNER);
+            context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
         }
     }
     static void visibilityChanged(boolean visible) {
@@ -868,14 +867,14 @@
     }
 
     /** Notifies the status bar to trigger screen pinning. */
-    @ProxyFromAnyToPrimaryUser
+    @ProxyFromAnyToSystemUser
     public static void startScreenPinning(Context context, SystemServicesProxy ssp) {
-        if (ssp.isForegroundUserOwner()) {
+        if (ssp.isForegroundUserSystem()) {
             onStartScreenPinning(context);
         } else {
             Intent intent = createLocalBroadcastIntent(context,
                     ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER);
-            context.sendBroadcastAsUser(intent, UserHandle.OWNER);
+            context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
         }
     }
     static void onStartScreenPinning(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 14fba2b..afa32cbdf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -526,10 +526,10 @@
     /**
      * Returns whether the foreground user is the owner.
      */
-    public boolean isForegroundUserOwner() {
+    public boolean isForegroundUserSystem() {
         if (mAm == null) return false;
 
-        return mAm.getCurrentUser() == UserHandle.USER_OWNER;
+        return mAm.getCurrentUser() == UserHandle.USER_SYSTEM;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index f8ff616..d8a202c 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -58,8 +58,4 @@
     }
 
     public abstract void onUserSwitched(int newUserId);
-
-    public boolean isCurrentUserOwner() {
-        return mCurrentUserId == UserHandle.USER_OWNER;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 31c94f7..46b00c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -79,8 +79,8 @@
         mBatteryInfo = IBatteryStats.Stub.asInterface(
                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
-        context.registerReceiverAsUser(
-                mReceiver, UserHandle.OWNER, new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
+        context.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM,
+                new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
     }
 
     public void setVisible(boolean visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index baac8ac..db2415a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -194,7 +194,7 @@
     public static Drawable getIcon(Context context, StatusBarIcon icon) {
         int userId = icon.user.getIdentifier();
         if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_OWNER;
+            userId = UserHandle.USER_SYSTEM;
         }
         return icon.icon.loadDrawableAsUser(context, userId);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index fcdd4b7..4f57906 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -149,7 +149,7 @@
             }
             return;
         }
-        StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.OWNER, iconId, 0, 0, "Demo");
+        StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo");
         StatusBarIconView v = new StatusBarIconView(getContext(), null, null);
         v.setTag(slot);
         v.set(icon);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index 71ee4e4..41d30c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -21,11 +21,13 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
@@ -71,6 +73,7 @@
     private static NavigationBarAppsModel sAppsModel;
 
     private final PackageManager mPackageManager;
+    private final UserManager mUserManager;
     private final LayoutInflater mLayoutInflater;
 
     // This view has two roles:
@@ -82,13 +85,26 @@
     // When the user is not dragging this member is null.
     private View mDragView;
 
+    private long mCurrentUserSerialNumber = -1;
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                int currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                onUserSwitched(currentUserId);
+            }
+        }
+    };
+
     public NavigationBarApps(Context context, AttributeSet attrs) {
         super(context, attrs);
         if (sAppsModel == null) {
             sAppsModel = new NavigationBarAppsModel(context);
-            sAppsModel.initialize();  // Load the saved icons, if any.
         }
         mPackageManager = context.getPackageManager();
+        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mLayoutInflater = LayoutInflater.from(context);
 
         // Dragging an icon removes and adds back the dragged icon. Use the layout transitions to
@@ -108,17 +124,32 @@
     @Override
     protected void onAttachedToWindow() {
       super.onAttachedToWindow();
-      // When an icon is dragged out of the pinned area this view's width changes, which causes
-      // the parent container's layout to change and the divider and recents icons to shift left.
-      // Animate the parent's CHANGING transition.
-      ViewGroup parent = (ViewGroup) getParent();
-      LayoutTransition transition = new LayoutTransition();
-      transition.disableTransitionType(LayoutTransition.APPEARING);
-      transition.disableTransitionType(LayoutTransition.DISAPPEARING);
-      transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
-      transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-      transition.enableTransitionType(LayoutTransition.CHANGING);
-      parent.setLayoutTransition(transition);
+        // When an icon is dragged out of the pinned area this view's width changes, which causes
+        // the parent container's layout to change and the divider and recents icons to shift left.
+        // Animate the parent's CHANGING transition.
+        ViewGroup parent = (ViewGroup) getParent();
+        LayoutTransition transition = new LayoutTransition();
+        transition.disableTransitionType(LayoutTransition.APPEARING);
+        transition.disableTransitionType(LayoutTransition.DISAPPEARING);
+        transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
+        transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+        transition.enableTransitionType(LayoutTransition.CHANGING);
+        parent.setLayoutTransition(transition);
+
+        mCurrentUserSerialNumber = mUserManager.getSerialNumberForUser(
+                new UserHandle(ActivityManager.getCurrentUser()));
+        sAppsModel.setCurrentUser(mCurrentUserSerialNumber);
+        recreateAppButtons();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mContext.unregisterReceiver(mBroadcastReceiver);
     }
 
     /**
@@ -433,14 +464,11 @@
             AppInfo appInfo = sAppsModel.getApp(indexOfChild(v));
             ComponentName component = appInfo.getComponentName();
 
-            UserManager userManager =
-                    (UserManager) getContext().getSystemService(Context.USER_SERVICE);
-
             long appUserSerialNumber = appInfo.getUserSerialNumber();
 
             UserHandle appUser = null;
             if (appUserSerialNumber != AppInfo.USER_UNSPECIFIED) {
-                appUser = userManager.getUserForSerialNumber(appUserSerialNumber);
+                appUser = mUserManager.getUserForSerialNumber(appUserSerialNumber);
             }
 
             int appUserId;
@@ -510,4 +538,15 @@
             Log.e(TAG, "Attempt to launch activity without category Intent.CATEGORY_LAUNCHER " + component);
         }
     }
+
+    private void onUserSwitched(int currentUserId) {
+        final long newUserSerialNumber =
+                mUserManager.getSerialNumberForUser(new UserHandle(currentUserId));
+
+        if (newUserSerialNumber != mCurrentUserSerialNumber) {
+            mCurrentUserSerialNumber = newUserSerialNumber;
+            sAppsModel.setCurrentUser(newUserSerialNumber);
+            recreateAppButtons();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
index 9f80d33..39f1304 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
@@ -19,16 +19,20 @@
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
-import android.os.UserHandle;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Data model and controller for app icons appearing in the navigation bar. The data is stored on
@@ -48,7 +52,7 @@
     private final static String VERSION_PREF = "version";
 
     // Current version number for preferences.
-    private final static int CURRENT_VERSION = 1;
+    private final static int CURRENT_VERSION = 2;
 
     // Preference name for the number of app icons.
     private final static String APP_COUNT_PREF = "app_count";
@@ -59,42 +63,99 @@
     // User serial number prefix for each app's info. The actual pref has an integer appended to it.
     private final static String APP_USER_PREFIX = "app_user_";
 
-    private final LauncherApps mLauncherApps;
+    // Character separating current user serial number from the user-specific part of a pref.
+    // Example "22|app_user_2" - when logged as user with serial 22, we'll use this pref for the
+    // user serial of the third app of the logged-in user.
+    private final static char USER_SEPARATOR = '|';
+
+    final Context mContext;
     private final SharedPreferences mPrefs;
 
     // Apps are represented as an ordered list of app infos.
     private final List<AppInfo> mApps = new ArrayList<AppInfo>();
 
-    public NavigationBarAppsModel(Context context) {
-        mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
-        mPrefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
-    }
+    // Serial number of the current user.
+    private long mCurrentUserSerialNumber = AppInfo.USER_UNSPECIFIED;
 
-    @VisibleForTesting
-    NavigationBarAppsModel(LauncherApps launcherApps, SharedPreferences prefs) {
-        mLauncherApps = launcherApps;
-        mPrefs = prefs;
+    public NavigationBarAppsModel(Context context) {
+        mContext = context;
+        mPrefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+
+        int version = mPrefs.getInt(VERSION_PREF, -1);
+        if (version != CURRENT_VERSION) {
+            // Since the data format changed, clean everything.
+            SharedPreferences.Editor edit = mPrefs.edit();
+            edit.clear();
+            edit.putInt(VERSION_PREF, CURRENT_VERSION);
+            edit.apply();
+        }
     }
 
     /**
-     * Initializes the model with a list of apps, either by loading it off disk or by supplying
-     * a default list.
+     * Reinitializes the model for a new user.
      */
-    public void initialize() {
-        if (mApps.size() > 0) {
-            Slog.e(TAG, "Model already initialized");
-            return;
-        }
+    public void setCurrentUser(long userSerialNumber) {
+        mCurrentUserSerialNumber = userSerialNumber;
 
-        // Check for an existing list of apps.
-        int version = mPrefs.getInt(VERSION_PREF, -1);
-        if (version == CURRENT_VERSION) {
+        mApps.clear();
+
+        int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
+        if (appCount >= 0) {
             loadAppsFromPrefs();
         } else {
+            // We switched to this user for the first time ever. This is a good opportunity to clean
+            // prefs for users deleted in the past.
+            removePrefsForDeletedUsers();
+
             addDefaultApps();
         }
     }
 
+    /**
+     * Removes prefs for users that don't exist on the device.
+     */
+    private void removePrefsForDeletedUsers() {
+        UserManager userManager =
+                (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        // Build a set of string representations of serial numbers of the device users.
+        final List<UserInfo> users = userManager.getUsers();
+        final int userCount = users.size();
+
+        final Set<String> userSerials = new HashSet<String> ();
+
+        for (int i = 0; i < userCount; ++i) {
+            userSerials.add(Long.toString(users.get(i).serialNumber));
+        }
+
+        // Walk though all prefs and delete ones which user is not in the string set.
+        final Map<String, ?> allPrefs = mPrefs.getAll();
+        final SharedPreferences.Editor edit = mPrefs.edit();
+
+        for (Map.Entry<String, ?> pref : allPrefs.entrySet()) {
+            final String key = pref.getKey();
+            if (key.equals(VERSION_PREF)) continue;
+
+            final int userSeparatorPos = key.indexOf(USER_SEPARATOR);
+
+            if (userSeparatorPos < 0) {
+                // Removing anomalous pref with no user.
+                edit.remove(key);
+                continue;
+            }
+
+            final String prefUserSerial = key.substring(0, userSeparatorPos);
+
+            if (!userSerials.contains(prefUserSerial)) {
+                // Removes pref for a not existing user.
+                edit.remove(key);
+                continue;
+            }
+        }
+
+        edit.apply();
+    }
+
     /** Returns the number of apps. */
     public int getAppCount() {
         return mApps.size();
@@ -123,11 +184,8 @@
     /** Saves the current model to disk. */
     public void savePrefs() {
         SharedPreferences.Editor edit = mPrefs.edit();
-        // The user might have removed icons, so clear all the old prefs.
-        edit.clear();
-        edit.putInt(VERSION_PREF, CURRENT_VERSION);
         int appCount = mApps.size();
-        edit.putInt(APP_COUNT_PREF, appCount);
+        edit.putInt(userPrefixed(APP_COUNT_PREF), appCount);
         for (int i = 0; i < appCount; i++) {
             final AppInfo appInfo = mApps.get(i);
             String componentNameString = appInfo.getComponentName().flattenToString();
@@ -140,7 +198,7 @@
 
     /** Loads the list of apps from SharedPreferences. */
     private void loadAppsFromPrefs() {
-        int appCount = mPrefs.getInt(APP_COUNT_PREF, -1);
+        int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
         for (int i = 0; i < appCount; i++) {
             String prefValue = mPrefs.getString(prefNameForApp(i), null);
             if (prefValue == null) {
@@ -154,27 +212,48 @@
         }
     }
 
+    @VisibleForTesting
+    protected int getCurrentUser() {
+        return ActivityManager.getCurrentUser();
+    }
+
     /** Adds the first few apps from the owner profile. Used for demo purposes. */
     private void addDefaultApps() {
         // Get a list of all app activities.
-        List<LauncherActivityInfo> apps =
-                mLauncherApps.getActivityList(
-                        null /* packageName */, new UserHandle(ActivityManager.getCurrentUser()));
-        int appCount = apps.size();
+        final Intent queryIntent = new Intent(Intent.ACTION_MAIN, null);
+        queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        final int currentUser = getCurrentUser();
+
+        final List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(
+                queryIntent, 0 /* flags */, currentUser);
+        final int appCount = apps.size();
         for (int i = 0; i < NUM_INITIAL_APPS && i < appCount; i++) {
-            LauncherActivityInfo activityInfo = apps.get(i);
-            mApps.add(new AppInfo(activityInfo.getComponentName(), AppInfo.USER_UNSPECIFIED));
+            ResolveInfo ri = apps.get(i);
+            ComponentName componentName = new ComponentName(
+                    ri.activityInfo.packageName, ri.activityInfo.name);
+            mApps.add(new AppInfo(componentName, AppInfo.USER_UNSPECIFIED));
         }
+
+        savePrefs();
+    }
+
+    /** Returns a pref prefixed with the serial number of the current user. */
+    private String userPrefixed(String pref) {
+        if (mCurrentUserSerialNumber == AppInfo.USER_UNSPECIFIED) {
+            throw new RuntimeException("Current user is not yet set");
+        }
+
+        return Long.toString(mCurrentUserSerialNumber) + USER_SEPARATOR + pref;
     }
 
     /** Returns the pref name for the app at a given index. */
-    private static String prefNameForApp(int index) {
-        return APP_PREF_PREFIX + Integer.toString(index);
+    private String prefNameForApp(int index) {
+        return userPrefixed(APP_PREF_PREFIX + Integer.toString(index));
     }
 
     /** Returns the pref name for the app's user at a given index. */
-    private static String prefUserForApp(int index) {
-        return APP_USER_PREFIX + Integer.toString(index);
+    private String prefUserForApp(int index) {
+        return userPrefixed(APP_USER_PREFIX + Integer.toString(index));
     }
 
 }
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 5d64abb9..2253cad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1076,6 +1076,7 @@
             if (shouldDisableNavbarGestures()) {
                 return false;
             }
+            MetricsLogger.action(mContext, MetricsLogger.ACTION_ASSIST_LONG_PRESS);
             mAssistManager.startAssist(new Bundle() /* args */);
             awakenDreams();
             if (mNavigationBarView != null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
index f46e76c..31007ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
@@ -18,24 +18,35 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
-import android.os.UserHandle;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
 import android.test.AndroidTestCase;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /** Tests for the data model for the navigation bar app icons. */
 public class NavigationBarAppsModelTest extends AndroidTestCase {
-    private LauncherApps mMockLauncherApps;
+    private PackageManager mMockPackageManager;
     private SharedPreferences mMockPrefs;
+    private SharedPreferences.Editor mMockEdit;
+    private UserManager mMockUserManager;
 
     private NavigationBarAppsModel mModel;
 
@@ -47,26 +58,44 @@
         System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
-        mMockLauncherApps = mock(LauncherApps.class);
+        final Context context = mock(Context.class);
+        mMockPackageManager = mock(PackageManager.class);
         mMockPrefs = mock(SharedPreferences.class);
-        mModel = new NavigationBarAppsModel(mMockLauncherApps, mMockPrefs);
+        mMockEdit = mock(SharedPreferences.Editor.class);
+        mMockUserManager = mock(UserManager.class);
+
+        when (context.getSharedPreferences(
+                "com.android.systemui.navbarapps", Context.MODE_PRIVATE)).thenReturn(mMockPrefs);
+        when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+        when(context.getPackageManager()).thenReturn(mMockPackageManager);
+
+        setContext(context);
+
+        when(mMockUserManager.getUsers()).thenReturn(new ArrayList<UserInfo>());
+        // Assume the version pref is present and equal to the current version.
+        when(mMockPrefs.getInt("version", -1)).thenReturn(2);
+        when(mMockPrefs.edit()).thenReturn(mMockEdit);
+
+        mModel = new NavigationBarAppsModel(context) {
+            @Override
+            protected int getCurrentUser() {
+                return 0;
+            }
+        };
     }
 
     /** Initializes the model from SharedPreferences for a few app activites. */
     private void initializeModelFromPrefs() {
-        // Assume the version pref is present.
-        when(mMockPrefs.getInt("version", -1)).thenReturn(1);
-
         // Assume several apps are stored.
-        when(mMockPrefs.getInt("app_count", -1)).thenReturn(3);
-        when(mMockPrefs.getString("app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("app_user_0", -1)).thenReturn(-1L);
-        when(mMockPrefs.getString("app_1", null)).thenReturn("package1/class1");
-        when(mMockPrefs.getLong("app_user_1", -1)).thenReturn(45L);
-        when(mMockPrefs.getString("app_2", null)).thenReturn("package2/class2");
-        when(mMockPrefs.getLong("app_user_2", -1)).thenReturn(239L);
+        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(3);
+        when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
+        when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(-1L);
+        when(mMockPrefs.getString("22|app_1", null)).thenReturn("package1/class1");
+        when(mMockPrefs.getLong("22|app_user_1", -1)).thenReturn(45L);
+        when(mMockPrefs.getString("22|app_2", null)).thenReturn("package2/class2");
+        when(mMockPrefs.getLong("22|app_user_2", -1)).thenReturn(239L);
 
-        mModel.initialize();
+        mModel.setCurrentUser(22L);
     }
 
     /** Tests initializing the model from SharedPreferences. */
@@ -83,22 +112,26 @@
 
     /** Tests initializing the model when the SharedPreferences aren't available. */
     public void testInitializeDefaultApps() {
-        // Assume the version pref isn't available.
-        when(mMockPrefs.getInt("version", -1)).thenReturn(-1);
+        // Assume the user's app count pref isn't available.
+        when(mMockPrefs.getInt("0|app_count", -1)).thenReturn(-1);
 
         // Assume some installed activities.
-        LauncherActivityInfo activity1 = mock(LauncherActivityInfo.class);
-        when(activity1.getComponentName()).thenReturn(new ComponentName("package1", "class1"));
-        LauncherActivityInfo activity2 = mock(LauncherActivityInfo.class);
-        when(activity2.getComponentName()).thenReturn(new ComponentName("package2", "class2"));
-        List<LauncherActivityInfo> apps = new ArrayList<LauncherActivityInfo>();
-        apps.add(activity1);
-        apps.add(activity2);
-        when(mMockLauncherApps.getActivityList(anyString(), any(UserHandle.class)))
-                .thenReturn(apps);
+        ActivityInfo ai1 = new ActivityInfo();
+        ai1.packageName = "package1";
+        ai1.name = "class1";
+        ActivityInfo ai2 = new ActivityInfo();
+        ai2.packageName = "package2";
+        ai2.name = "class2";
+        ResolveInfo ri1 = new ResolveInfo();
+        ri1.activityInfo = ai1;
+        ResolveInfo ri2 = new ResolveInfo();
+        ri2.activityInfo = ai2;
+        when(mMockPackageManager
+                .queryIntentActivitiesAsUser(any(Intent.class), eq(0), eq(0)))
+                .thenReturn(Arrays.asList(ri1, ri2));
 
-        // Initializing the model should load the installed activities.
-        mModel.initialize();
+        // Setting the user should load the installed activities.
+        mModel.setCurrentUser(0L);
         assertEquals(2, mModel.getAppCount());
         assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
         assertEquals(-1L, mModel.getApp(0).getUserSerialNumber());
@@ -108,19 +141,16 @@
 
     /** Tests initializing the model if one of the prefs is missing. */
     public void testInitializeWithMissingPref() {
-        // Assume the version pref is present.
-        when(mMockPrefs.getInt("version", -1)).thenReturn(1);
-
         // Assume two apps are nominally stored.
-        when(mMockPrefs.getInt("app_count", -1)).thenReturn(2);
-        when(mMockPrefs.getString("app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("app_user_0", -1)).thenReturn(239L);
+        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(2);
+        when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
+        when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(239L);
 
         // But assume one pref is missing.
-        when(mMockPrefs.getString("app_1", null)).thenReturn(null);
+        when(mMockPrefs.getString("22|app_1", null)).thenReturn(null);
 
         // Initializing the model should load from prefs and skip the missing one.
-        mModel.initialize();
+        mModel.setCurrentUser(22L);
         assertEquals(1, mModel.getAppCount());
         assertEquals("package0/class0", mModel.getApp(0).getComponentName().flattenToString());
         assertEquals(239L, mModel.getApp(0).getUserSerialNumber());
@@ -130,15 +160,64 @@
     public void testSavePrefs() {
         initializeModelFromPrefs();
 
-        SharedPreferences.Editor mockEdit = mock(SharedPreferences.Editor.class);
-        when(mMockPrefs.edit()).thenReturn(mockEdit);
-
         mModel.savePrefs();
-        verify(mockEdit).clear();  // Old prefs were removed.
-        verify(mockEdit).putInt("version", 1);
-        verify(mockEdit).putInt("app_count", 3);
-        verify(mockEdit).putString("app_0", "package0/class0");
-        verify(mockEdit).putString("app_1", "package1/class1");
-        verify(mockEdit).putString("app_2", "package2/class2");
+        verify(mMockEdit).putInt("22|app_count", 3);
+        verify(mMockEdit).putString("22|app_0", "package0/class0");
+        verify(mMockEdit).putLong("22|app_user_0", -1L);
+        verify(mMockEdit).putString("22|app_1", "package1/class1");
+        verify(mMockEdit).putLong("22|app_user_1", 45L);
+        verify(mMockEdit).putString("22|app_2", "package2/class2");
+        verify(mMockEdit).putLong("22|app_user_2", 239L);
+        verify(mMockEdit).apply();
+        verifyNoMoreInteractions(mMockEdit);
+    }
+
+    /** Tests cleaning all prefs on a version change. */
+    public void testVersionChange() {
+        // Assume the version pref changed.
+        when(mMockPrefs.getInt("version", -1)).thenReturn(1);
+
+        new NavigationBarAppsModel(getContext());
+        verify(mMockEdit).clear();
+        verify(mMockEdit).putInt("version", 2);
+        verify(mMockEdit).apply();
+        verifyNoMoreInteractions(mMockEdit);
+    }
+
+    /** Tests cleaning prefs for deleted users. */
+    public void testCleaningDeletedUsers() {
+        // Users on the device.
+        final UserInfo user1 = new UserInfo(11, "", 0);
+        user1.serialNumber = 1111;
+        final UserInfo user2 = new UserInfo(13, "", 0);
+        user2.serialNumber = 1313;
+
+        when(mMockUserManager.getUsers()).thenReturn(Arrays.asList(user1, user2));
+
+        when(mMockPrefs.edit()).
+                thenReturn(mMockEdit).
+                thenReturn(mock(SharedPreferences.Editor.class));
+
+        // Assume the user's app count pref isn't available. This will trigger clearing deleted
+        // users' prefs.
+        when(mMockPrefs.getInt("0|app_count", -1)).thenReturn(-1);
+
+        final Map allPrefs = new HashMap<String, Object>();
+        allPrefs.put("version", null);
+        allPrefs.put("some_strange_pref", null);
+        allPrefs.put("", null);
+        allPrefs.put("|", null);
+        allPrefs.put("1313|app_count", null);
+        allPrefs.put("1212|app_count", null);
+        when(mMockPrefs.getAll()).thenReturn(allPrefs);
+
+        // Setting the user should remove prefs for deleted users.
+        mModel.setCurrentUser(0L);
+        verify(mMockEdit).remove("some_strange_pref");
+        verify(mMockEdit).remove("");
+        verify(mMockEdit).remove("|");
+        verify(mMockEdit).remove("1212|app_count");
+        verify(mMockEdit).apply();
+        verifyNoMoreInteractions(mMockEdit);
     }
 }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 2a3492b..45c020c 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -25,6 +25,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -509,6 +510,7 @@
             }
         }
 
+        String[] uidPackageNames = getPackagesForUid(uid);
         ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
 
         ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
@@ -516,12 +518,13 @@
             final int callbackCount = callbacks.size();
             for (int i = 0; i < callbackCount; i++) {
                 Callback callback = callbacks.get(i);
+                ArraySet<String> changedPackages = new ArraySet<>();
+                Collections.addAll(changedPackages, uidPackageNames);
                 callbackSpecs = new ArrayMap<>();
-                callbackSpecs.put(callback, null);
+                callbackSpecs.put(callback, changedPackages);
             }
         }
 
-        String[] uidPackageNames = getPackagesForUid(uid);
         for (String uidPackageName : uidPackageNames) {
             callbacks = mPackageModeWatchers.get(uidPackageName);
             if (callbacks != null) {
@@ -931,7 +934,6 @@
         }
         return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
                 Binder.getCallingUid(), proxyPackageName);
-
     }
 
     @Override
@@ -1266,7 +1268,7 @@
                         String tagName = parser.getName();
                         if (tagName.equals("pkg")) {
                             readPackage(parser);
-                        } if (tagName.equals("uid")) {
+                        } else if (tagName.equals("uid")) {
                             readUidOps(parser);
                         } else {
                             Slog.w(TAG, "Unknown element under <app-ops>: "
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8ca5ac1..028460c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4097,6 +4097,16 @@
         }
         if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) {
             final int oldScore = nai.getCurrentScore();
+            if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) !=
+                    networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+                try {
+                    mNetd.setNetworkPermission(nai.network.netId,
+                            networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ?
+                                    null : NetworkManagementService.PERMISSION_SYSTEM);
+                } catch (RemoteException e) {
+                    loge("Exception in setNetworkPermission: " + e);
+                }
+            }
             synchronized (nai) {
                 nai.networkCapabilities = networkCapabilities;
             }
@@ -4564,7 +4574,10 @@
                             (networkAgent.networkMisc == null ||
                                 !networkAgent.networkMisc.allowBypass));
                 } else {
-                    mNetd.createPhysicalNetwork(networkAgent.network.netId);
+                    mNetd.createPhysicalNetwork(networkAgent.network.netId,
+                            networkAgent.networkCapabilities.hasCapability(
+                                    NET_CAPABILITY_NOT_RESTRICTED) ?
+                                    null : NetworkManagementService.PERMISSION_SYSTEM);
                 }
             } catch (Exception e) {
                 loge("Error creating network " + networkAgent.network.netId + ": "
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 64ee5f1..4e11070 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -3555,7 +3555,7 @@
                     ? new File(Environment.getDataDirectory(), SYSTEM_PATH)
                     : Environment.getUserSystemDirectory(userId);
             final File inputMethodDir = new File(systemDir, INPUT_METHOD_PATH);
-            if (!inputMethodDir.mkdirs()) {
+            if (!inputMethodDir.exists() && !inputMethodDir.mkdirs()) {
                 Slog.w(TAG, "Couldn't create dir.: " + inputMethodDir.getAbsolutePath());
             }
             final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 6a40d4f..dd19c6a 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -131,6 +131,19 @@
      */
     public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
 
+    /**
+     * String to pass to netd to indicate that a network is only accessible
+     * to apps that have the CHANGE_NETWORK_STATE permission.
+     */
+    public static final String PERMISSION_NETWORK = "NETWORK";
+
+    /**
+     * String to pass to netd to indicate that a network is only
+     * accessible to system apps and those with the CONNECTIVITY_INTERNAL
+     * permission.
+     */
+    public static final String PERMISSION_SYSTEM = "SYSTEM";
+
     class NetdResponseCode {
         /* Keep in sync with system/netd/server/ResponseCode.h */
         public static final int InterfaceListResult       = 110;
@@ -2329,11 +2342,15 @@
     }
 
     @Override
-    public void createPhysicalNetwork(int netId) {
+    public void createPhysicalNetwork(int netId, String permission) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "create", netId);
+            if (permission != null) {
+                mConnector.execute("network", "create", netId, permission);
+            } else {
+                mConnector.execute("network", "create", netId);
+            }
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -2425,6 +2442,22 @@
     }
 
     @Override
+    public void setNetworkPermission(int netId, String permission) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            if (permission != null) {
+                mConnector.execute("network", "permission", "network", "set", permission, netId);
+            } else {
+                mConnector.execute("network", "permission", "network", "clear", netId);
+            }
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+
+    @Override
     public void setPermission(String permission, int[] uids) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 32fd56a..83e8db0 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -527,14 +527,14 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot get secrets for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -627,14 +627,14 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         if (key == null) throw new IllegalArgumentException("key is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot get user data for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -664,22 +664,32 @@
 
         final long identityToken = clearCallingIdentity();
         try {
-            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
-                    authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
-            AuthenticatorDescription[] types =
-                    new AuthenticatorDescription[authenticatorCollection.size()];
-            int i = 0;
-            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
-                    : authenticatorCollection) {
-                types[i] = authenticator.type;
-                i++;
-            }
-            return types;
+            return getAuthenticatorTypesInternal(userId);
+
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    /**
+     * Should only be called inside of a clearCallingIdentity block.
+     */
+    private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
+        Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
+                authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
+        AuthenticatorDescription[] types =
+                new AuthenticatorDescription[authenticatorCollection.size()];
+        int i = 0;
+        for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
+                : authenticatorCollection) {
+            types[i] = authenticator.type;
+            i++;
+        }
+        return types;
+    }
+
+
+
     private boolean isCrossUser(int callingUid, int userId) {
         return (userId != UserHandle.getCallingUserId()
                 && callingUid != Process.myUid()
@@ -697,7 +707,8 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot explicitly add accounts of type: %s",
                     callingUid,
@@ -713,12 +724,10 @@
          */
 
         // fails if the account already exists
-        int uid = getCallingUid();
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            return addAccountInternal(accounts, account, password, extras, false, uid);
+            return addAccountInternal(accounts, account, password, extras, false, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -794,25 +803,26 @@
         if (account == null) {
             throw new IllegalArgumentException("account is null");
         }
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot notify authentication for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = Binder.getCallingUserHandle().getIdentifier();
+
         if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
             return false;
         }
-        int user = UserHandle.getCallingUserId();
+
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(user);
+            UserAccounts accounts = getUserAccounts(userId);
+            return updateLastAuthenticatedTime(account);
         } finally {
             restoreCallingIdentity(identityToken);
         }
-        return updateLastAuthenticatedTime(account);
     }
 
     private boolean updateLastAuthenticatedTime(Account account) {
@@ -985,8 +995,9 @@
         if (response == null) throw new IllegalArgumentException("response is null");
         if (account == null) throw new IllegalArgumentException("account is null");
         if (features == null) throw new IllegalArgumentException("features is null");
-        checkReadAccountsPermitted(callingUid, account.type);
         int userId = UserHandle.getCallingUserId();
+        checkReadAccountsPermitted(callingUid, account.type, userId);
+
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1062,14 +1073,14 @@
                 + ", pid " + Binder.getCallingPid());
         }
         if (accountToRename == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(accountToRename.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot rename accounts of type: %s",
                     callingUid,
                     accountToRename.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1211,14 +1222,15 @@
          * authenticator.  This will let users remove accounts (via Settings in the system) but not
          * arbitrary applications (like competing authenticators).
          */
-        if (!isAccountManagedByCaller(account.type, callingUid) && !isSystemUid(callingUid)) {
+        UserHandle user = new UserHandle(userId);
+        if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
+                && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot remove accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-
         if (!canUserModifyAccounts(userId)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
@@ -1235,10 +1247,7 @@
             }
             return;
         }
-
-        UserHandle user = new UserHandle(userId);
         long identityToken = clearCallingIdentity();
-
         UserAccounts accounts = getUserAccounts(userId);
         cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
         synchronized(accounts.credentialsPermissionNotificationIds) {
@@ -1268,6 +1277,7 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
+        int userId = Binder.getCallingUserHandle().getIdentifier();
         if (account == null) {
             /*
              * Null accounts should result in returning false, as per
@@ -1275,22 +1285,18 @@
              */
             Log.e(TAG, "account is null");
             return false;
-        } else if (!isAccountManagedByCaller(account.type, callingUid)) {
+        } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot explicitly add accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-
         UserAccounts accounts = getUserAccountsForCaller();
-        int userId = Binder.getCallingUserHandle().getIdentifier();
         if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
             return false;
         }
-
         logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
-
         long identityToken = clearCallingIdentity();
         try {
             return removeAccountInternal(accounts, account);
@@ -1524,14 +1530,14 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot peek the authtokens associated with accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1552,14 +1558,14 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot set auth tokens associated with accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1578,14 +1584,14 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot set secrets for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1642,14 +1648,14 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot clear passwords for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1670,14 +1676,14 @@
         }
         if (key == null) throw new IllegalArgumentException("key is null");
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot set user data for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1840,8 +1846,8 @@
 
         // skip the check if customTokens
         final int callerUid = Binder.getCallingUid();
-        final boolean permissionGranted = customTokens ||
-            permissionIsGranted(account, authTokenType, callerUid);
+        final boolean permissionGranted =
+                customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
 
         // Get the calling package. We will use it for the purpose of caching.
         final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
@@ -2363,14 +2369,14 @@
         }
         if (response == null) throw new IllegalArgumentException("response is null");
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
-        if (!isAccountManagedByCaller(accountType, callingUid) && !isSystemUid(callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot edit authenticator properites for account type: %s",
                     callingUid,
                     accountType);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -2493,20 +2499,22 @@
     }
 
     /**
-     * Returns the accounts for a specific user
+     * Returns the accounts visible to the client within the context of a specific user
      * @hide
      */
     public Account[] getAccounts(int userId) {
         int callingUid = Binder.getCallingUid();
-        if (!isReadAccountsPermitted(callingUid, null)) {
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        if (visibleAccountTypes.isEmpty()) {
             return new Account[0];
         }
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(userId);
-            synchronized (accounts.cacheLock) {
-                return getAccountsFromCacheLocked(accounts, null, callingUid, null);
-            }
+            return getAccountsInternal(
+                    userId,
+                    callingUid,
+                    null,  // packageName
+                    visibleAccountTypes);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -2588,22 +2596,52 @@
             callingUid = packageUid;
         }
 
-        // Authenticators should be able to see their own accounts regardless of permissions.
-        if (TextUtils.isEmpty(type) && !isReadAccountsPermitted(callingUid, type)) {
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        if (visibleAccountTypes.isEmpty()
+                || (type != null && !visibleAccountTypes.contains(type))) {
             return new Account[0];
-        }
+        } else if (visibleAccountTypes.contains(type)) {
+            // Prune the list down to just the requested type.
+            visibleAccountTypes = new ArrayList<>();
+            visibleAccountTypes.add(type);
+        } // else aggregate all the visible accounts (it won't matter if the list is empty).
 
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(userId);
-            synchronized (accounts.cacheLock) {
-                return getAccountsFromCacheLocked(accounts, type, callingUid, callingPackage);
-            }
+            return getAccountsInternal(
+                    userId,
+                    callingUid,
+                    callingPackage,
+                    visibleAccountTypes);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    private Account[] getAccountsInternal(
+            int userId,
+            int callingUid,
+            String callingPackage,
+            List<String> visibleAccountTypes) {
+        UserAccounts accounts = getUserAccounts(userId);
+        synchronized (accounts.cacheLock) {
+            UserAccounts userAccounts = getUserAccounts(userId);
+            ArrayList<Account> visibleAccounts = new ArrayList<>();
+            for (String visibleType : visibleAccountTypes) {
+                Account[] accountsForType = getAccountsFromCacheLocked(
+                        userAccounts, visibleType, callingUid, callingPackage);
+                if (accountsForType != null) {
+                    visibleAccounts.addAll(Arrays.asList(accountsForType));
+                }
+            }
+            Account[] result = new Account[visibleAccounts.size()];
+            for (int i = 0; i < visibleAccounts.size(); i++) {
+                result[i] = visibleAccounts.get(i);
+            }
+            return result;
+        }
+    }
+
     @Override
     public boolean addSharedAccountAsUser(Account account, int userId) {
         userId = handleIncomingUser(userId);
@@ -2739,8 +2777,12 @@
         }
         if (response == null) throw new IllegalArgumentException("response is null");
         if (type == null) throw new IllegalArgumentException("accountType is null");
-        if (!isReadAccountsPermitted(callingUid, type)) {
+        int userId = UserHandle.getCallingUserId();
+
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        if (!visibleAccountTypes.contains(type)) {
             Bundle result = new Bundle();
+            // Need to return just the accounts that are from matching signatures.
             result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
             try {
                 response.onResult(result);
@@ -2749,7 +2791,6 @@
             }
             return;
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts userAccounts = getUserAccounts(userId);
@@ -2763,7 +2804,11 @@
                 onResult(response, result);
                 return;
             }
-            new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features,
+            new GetAccountsByTypeAndFeatureSession(
+                    userAccounts,
+                    response,
+                    type,
+                    features,
                     callingUid).bind();
         } finally {
             restoreCallingIdentity(identityToken);
@@ -3696,10 +3741,11 @@
         return false;
     }
 
-    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
+    private boolean permissionIsGranted(
+            Account account, String authTokenType, int callerUid, int userId) {
         final boolean isPrivileged = isPrivileged(callerUid);
         final boolean fromAuthenticator = account != null
-                && isAccountManagedByCaller(account.type, callerUid);
+                && isAccountManagedByCaller(account.type, callerUid, userId);
         final boolean hasExplicitGrants = account != null
                 && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -3711,23 +3757,45 @@
         return fromAuthenticator || hasExplicitGrants || isPrivileged;
     }
 
-    private boolean isAccountManagedByCaller(String accountType, int callingUid) {
+    private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId) {
         if (accountType == null) {
             return false;
+        } else {
+            return getTypesVisibleToCaller(callingUid, userId).contains(accountType);
         }
-        final int callingUserId = UserHandle.getUserId(callingUid);
+    }
+
+    private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
+        if (accountType == null) {
+            return false;
+        } else {
+            return getTypesManagedByCaller(callingUid, userId).contains(accountType);
+        }
+    }
+
+    private List<String> getTypesVisibleToCaller(int callingUid, int userId) {
+        boolean isPermitted =
+                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
+                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+        Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
+        return getTypesForCaller(callingUid, userId, isPermitted);
+    }
+
+    private List<String> getTypesManagedByCaller(int callingUid, int userId) {
+        return getTypesForCaller(callingUid, userId, false);
+    }
+
+    private List<String> getTypesForCaller(
+            int callingUid, int userId, boolean isOtherwisePermitted) {
+        List<String> managedAccountTypes = new ArrayList<>();
         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
-                mAuthenticatorCache.getAllServices(callingUserId)) {
-            if (serviceInfo.type.type.equals(accountType)) {
-                /*
-                 * We can't simply compare uids because uids can be recycled before the
-                 * authenticator cache is updated.
-                 */
-                final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
-                return sigChk == PackageManager.SIGNATURE_MATCH;
+                mAuthenticatorCache.getAllServices(userId)) {
+            final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+            if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
+                managedAccountTypes.add(serviceInfo.type.type);
             }
         }
-        return false;
+        return managedAccountTypes;
     }
 
     private boolean isAccountPresentForCaller(String accountName, String accountType) {
@@ -3792,28 +3860,12 @@
         return false;
     }
 
-    private boolean isReadAccountsPermitted(int callingUid, String accountType) {
-        /*
-         * Settings app (which is in the same uid as AcocuntManagerService), apps with the
-         * GET_ACCOUNTS permission or authenticators that own the account type should be able to
-         * access accounts of the specified account.
-         */
-        boolean isPermitted =
-                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
-                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
-        boolean isAccountManagedByCaller = isAccountManagedByCaller(accountType, callingUid);
-        Log.w(TAG, String.format(
-                "isReadAccountPermitted: isPermitted: %s, isAM: %s",
-                isPermitted,
-                isAccountManagedByCaller));
-        return isPermitted || isAccountManagedByCaller;
-    }
-
     /** Succeeds if any of the specified permissions are granted. */
     private void checkReadAccountsPermitted(
             int callingUid,
-            String accountType) {
-        if (!isReadAccountsPermitted(callingUid, accountType)) {
+            String accountType,
+            int userId) {
+        if (!isAccountVisibleToCaller(accountType, callingUid, userId)) {
             String msg = String.format(
                     "caller uid %s cannot access %s accounts",
                     callingUid,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7f4746e..147a5fd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4252,14 +4252,13 @@
      * @param token The Binder token referencing the Activity we want to finish.
      * @param resultCode Result code, if any, from this Activity.
      * @param resultData Result data (Intent), if any, from this Activity.
-     * @param finishTask Whether to finish the task associated with this Activity.  Only applies to
-     *            the root Activity in the task.
+     * @param finishTask Whether to finish the task associated with this Activity.
      *
      * @return Returns true if the activity successfully finished, or false if it is still running.
      */
     @Override
     public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
-            boolean finishTask) {
+            int finishTask) {
         // Refuse possible leaked file descriptors
         if (resultData != null && resultData.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -4306,7 +4305,8 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 boolean res;
-                if (finishTask && r == rootR) {
+                if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
+                        || (finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY && r == rootR)) {
                     // If requested, remove the task that is associated to this activity only if it
                     // was the root activity in the task. The result code and data is ignored
                     // because we don't support returning them across task boundaries.
@@ -8930,6 +8930,35 @@
     }
 
     @Override
+    public int getActivityStackId(IBinder token) throws RemoteException {
+        synchronized (this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack == null) {
+                throw new IllegalArgumentException(
+                        "getActivityStackId: No stack for token=" + token);
+            }
+            return stack.mStackId;
+        }
+    }
+
+    @Override
+    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException {
+        synchronized(this) {
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r == null) {
+                    throw new IllegalArgumentException(
+                            "moveActivityToStack: No activity record matching token=" + token);
+                }
+                moveTaskToStack(r.task.taskId, stackId, true /*toTop*/);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                 "moveTaskToStack()");
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e6c8d43..e083709 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -25,7 +25,9 @@
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 
+import android.graphics.Rect;
 import android.util.ArraySet;
+import android.view.IApplicationToken;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.BatteryStatsImpl;
@@ -478,7 +480,15 @@
                 mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
     }
 
-    final void moveToFront(String reason) {
+    void moveToFront(String reason) {
+        moveToFront(reason, null);
+    }
+
+    /**
+     * @param reason The reason for moving the stack to the front.
+     * @param task If non-null, the task will be moved to the top of the stack.
+     * */
+    void moveToFront(String reason, TaskRecord task) {
         if (isAttached()) {
             final boolean homeStack = isHomeStack()
                     || (mActivityContainer.mParentActivity != null
@@ -496,7 +506,11 @@
             if (isOnHomeDisplay()) {
                 mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
             }
-            final TaskRecord task = topTask();
+            if (task != null) {
+                insertTaskAtTop(task, null);
+            } else {
+                task = topTask();
+            }
             if (task != null) {
                 mWindowManager.moveTaskToTop(task.taskId);
             }
@@ -542,6 +556,10 @@
                 if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
                 continue;
             }
+            if (r.mActivityType != target.mActivityType) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
+                continue;
+            }
 
             final Intent taskIntent = task.intent;
             final Intent affinityIntent = task.affinityIntent;
@@ -2145,11 +2163,7 @@
                                 + task, new RuntimeException("here").fillInStackTrace());
                         task.addActivityToTop(r);
                         r.putInHistory();
-                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
-                                r.userId, r.info.configChanges, task.voiceSession != null,
-                                r.mLaunchTaskBehind);
+                        addAppToken(r, task);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
                         }
@@ -2209,10 +2223,7 @@
                         : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
-            mWindowManager.addAppToken(task.mActivities.indexOf(r),
-                    r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
+            addAppToken(r, task);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -2261,10 +2272,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.
-            mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                    r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
+            addAppToken(r, task);
             ActivityOptions.abort(options);
             options = null;
         }
@@ -2378,8 +2386,7 @@
                             + " out to new task " + target.task);
                 }
 
-                final int targetTaskId = targetTask.taskId;
-                mWindowManager.setAppTask(target.appToken, targetTaskId);
+                setAppTask(target, targetTask);
 
                 boolean noOptions = canMoveOptions;
                 final int start = replyChainEnd < 0 ? i : replyChainEnd;
@@ -2404,10 +2411,10 @@
                     p.setTask(targetTask, null);
                     targetTask.addActivityAtBottom(p);
 
-                    mWindowManager.setAppTask(p.appToken, targetTaskId);
+                    setAppTask(p, targetTask);
                 }
 
-                mWindowManager.moveTaskToBottom(targetTaskId);
+                mWindowManager.moveTaskToBottom(targetTask.taskId);
                 if (VALIDATE_TOKENS) {
                     validateAppTokensLocked();
                 }
@@ -2546,7 +2553,7 @@
                                 + " callers=" + Debug.getCallers(3));
                         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                 + " from " + srcPos + " in to resetting task " + task);
-                        mWindowManager.setAppTask(p.appToken, taskId);
+                        setAppTask(p, task);
                     }
                     mWindowManager.moveTaskToTop(taskId);
                     if (VALIDATE_TOKENS) {
@@ -4408,6 +4415,30 @@
         }
     }
 
+    void addAppToken(ActivityRecord r, TaskRecord task) {
+        final Rect bounds = task.getLaunchBounds();
+        final Configuration config =
+                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+                        r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                        (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
+                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
+                        bounds);
+        if (config != null) {
+            task.updateOverrideConfiguration(config, bounds);
+        }
+        r.taskConfigOverride = task.mOverrideConfig;
+    }
+
+    private void setAppTask(ActivityRecord r, TaskRecord task) {
+        final Rect bounds = task.getLaunchBounds();
+        final Configuration config =
+                mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
+        if (config != null) {
+            task.updateOverrideConfiguration(config, bounds);
+        }
+        r.taskConfigOverride = task.mOverrideConfig;
+    }
+
     public int getStackId() {
         return mStackId;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c22bff3..4a0fd89 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,15 +17,7 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.app.ActivityManager.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.FIRST_STATIC_STACK_ID;
-import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.HOME_STACK_ID;
-import static android.app.ActivityManager.LAST_STATIC_STACK_ID;
-import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
-import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.ActivityManager.*;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -1789,20 +1781,22 @@
                 return mFocusedStack;
             }
 
+            // We first try to put the task in the first dynamic stack.
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 stack = homeDisplayStacks.get(stackNdx);
-                if (!stack.isHomeStack()) {
+                final boolean isDynamicStack = stack.mStackId >= FIRST_DYNAMIC_STACK_ID;
+                if (isDynamicStack) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                             "computeStackFocus: Setting focused stack=" + stack);
                     return stack;
                 }
             }
 
-            // TODO (multi-window): Change to select task id based on if the task should on in
-            // fullscreen, freefrom, or sid-by-side stack.
+            // If there is no suitable dynamic stack then we figure out which static stack to use.
             stack = getStack(
-                    FULLSCREEN_WORKSPACE_STACK_ID,
+                    task != null
+                            ? task.getLaunchStackId(mFocusedStack) : FULLSCREEN_WORKSPACE_STACK_ID,
                     true /*createStaticStackIfNeeded*/,
                     true /*createOnTop*/);
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
@@ -1822,7 +1816,7 @@
             Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
             return false;
         }
-        task.stack.moveToFront(reason);
+        task.stack.moveToFront(reason, task);
         return true;
     }
 
@@ -2899,7 +2893,7 @@
                 Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
                 continue;
             }
-            task.updateOverrideConfiguration(newTaskConfigs.get(i));
+            task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
         }
 
         if (r != null) {
@@ -2924,16 +2918,20 @@
             return;
         }
 
-        task.mBounds = new Rect(bounds);
-
         if (!mWindowManager.isValidTaskId(task.taskId)) {
             // Task doesn't exist in window manager yet (e.g. was restored from recents).
-            // No need to do anything else until we add the task to window manager.
+            // All we can do for now is update the bounds so it can be used when the task is
+            // added to window manager.
+            task.mBounds = task.mLastNonFullscreenBounds = new Rect(bounds);
+            if (task.stack != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+                // re-restore the task so it can have the proper stack association.
+                restoreRecentTaskLocked(task);
+            }
             return;
         }
 
         final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
-        if (task.updateOverrideConfiguration(overrideConfig)) {
+        if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
             ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
                 final ActivityStack stack = task.stack;
@@ -2972,13 +2970,21 @@
     }
 
     private boolean restoreRecentTaskLocked(TaskRecord task) {
-        // TODO (multi-window): Change to select task id based on if the task should on in
-        // fullscreen, freefrom, or sid-by-side stack.
-        // Always put task for lean back device in home stack since they only have one stack,
-        // else use the preferred stack ID to get the stack we should use if it already exists.
-        ActivityStack stack = mLeanbackOnlyDevice ? mHomeStack :
-                getStack(FULLSCREEN_WORKSPACE_STACK_ID,
-                        true /*createStaticStackIfNeeded*/, false /*createOnTop*/);
+        final int stackId =
+                mLeanbackOnlyDevice ? mHomeStack.mStackId : task.getLaunchStackId(mFocusedStack);
+        if (task.stack != null) {
+            // Task has already been restored once. See if we need to do anything more
+            if (task.stack.mStackId == stackId) {
+                // Nothing else to do since it is already restored in the right stack.
+                return true;
+            }
+            // Remove current stack association, so we can re-associate the task with the
+            // right stack below.
+            task.stack.removeTask(task, "restoreRecentTaskLocked", false /*notMoving*/);
+        }
+
+        ActivityStack stack =
+                getStack(stackId, true /*createStaticStackIfNeeded*/, false /*createOnTop*/);
 
         if (stack == null) {
             // What does this mean??? Not sure how we would get here...
@@ -2992,12 +2998,7 @@
                 "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-            final ActivityRecord r = activities.get(activityNdx);
-            mWindowManager.addAppToken(0, r.appToken, task.taskId, stack.mStackId,
-                    r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
-                    r.userId, r.info.configChanges, task.voiceSession != null,
-                    r.mLaunchTaskBehind);
+            stack.addAppToken(activities.get(activityNdx), task);
         }
         return true;
     }
@@ -3015,6 +3016,15 @@
             task.stack.removeTask(task, "moveTaskToStack", false /* notMoving */);
         }
         stack.addTask(task, toTop, true);
+
+        // Make sure the task has the appropriate bounds/size for the stack it is in.
+        if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
+            resizeTaskLocked(task, null);
+        } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
+                && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
+            resizeTaskLocked(task, task.mLastNonFullscreenBounds);
+        }
+
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         stack.ensureActivitiesVisibleLocked(null, 0);
@@ -3819,6 +3829,7 @@
         }
         info.taskIds = taskIds;
         info.taskNames = taskNames;
+        info.taskBounds = taskBounds;
         return info;
     }
 
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index a892c7d..dd57f80 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.HOME_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -94,7 +97,7 @@
     private static final String ATTR_CALLING_PACKAGE = "calling_package";
     private static final String ATTR_RESIZEABLE = "resizeable";
     private static final String ATTR_PRIVILEGED = "privileged";
-    private static final String ATTR_BOUNDS = "bounds";
+    private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
@@ -207,6 +210,10 @@
 
     // Bounds of the Task. null for fullscreen tasks.
     Rect mBounds = null;
+    // Last non-fullscreen bounds the task was launched in or resized to.
+    // The information is persisted and used to determine the appropriate stack to launch the
+    // task into on restore.
+    Rect mLastNonFullscreenBounds = null;
 
     Configuration mOverrideConfig = Configuration.EMPTY;
 
@@ -301,7 +308,7 @@
         mCallingPackage = callingPackage;
         mResizeable = resizeable;
         mPrivileged = privileged;
-        mBounds = bounds;
+        mBounds = mLastNonFullscreenBounds = bounds;
     }
 
     void touchActiveTime() {
@@ -799,7 +806,8 @@
     }
 
     boolean isLockTaskWhitelistedLocked() {
-        if (mCallingPackage == null) {
+        String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
+        if (pkg == null) {
             return false;
         }
         String[] packages = mService.mLockTaskPackages.get(userId);
@@ -807,7 +815,7 @@
             return false;
         }
         for (int i = packages.length - 1; i >= 0; --i) {
-            if (mCallingPackage.equals(packages[i])) {
+            if (pkg.equals(packages[i])) {
                 return true;
             }
         }
@@ -963,8 +971,9 @@
         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
         out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
         out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
-        if (mBounds != null) {
-            out.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
+        if (mLastNonFullscreenBounds != null) {
+            out.attribute(
+                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
         }
 
         if (affinityIntent != null) {
@@ -1084,7 +1093,7 @@
                 resizeable = Boolean.valueOf(attrValue);
             } else if (ATTR_PRIVILEGED.equals(attrName)) {
                 privileged = Boolean.valueOf(attrValue);
-            } else if (ATTR_BOUNDS.equals(attrName)) {
+            } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
                 bounds = Rect.unflattenFromString(attrValue);
             } else {
                 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
@@ -1155,16 +1164,53 @@
         return task;
     }
 
-    boolean updateOverrideConfiguration(Configuration newConfig) {
+    boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
         Configuration oldConfig = mOverrideConfig;
         mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
         // We override the configuration only when the task's dimensions are different from the
         // display. In this manner, we know that if the override configuration is empty, the task
         // is necessarily fullscreen.
         mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+        if (mFullscreen) {
+            if (mBounds != null) {
+                mLastNonFullscreenBounds = mBounds;
+            }
+            mBounds = null;
+        } else {
+            mBounds = mLastNonFullscreenBounds = new Rect(bounds);
+        }
         return !mOverrideConfig.equals(oldConfig);
     }
 
+    /** Returns the stack that should be used to launch this task. */
+    int getLaunchStackId(ActivityStack focusStack) {
+        if (stack != null) {
+            // We are already in a stack silly...
+            return stack.mStackId;
+        }
+        if (isHomeTask()) {
+            return HOME_STACK_ID;
+        }
+        if (focusStack != null && focusStack.mStackId != HOME_STACK_ID) {
+            // Like it or not you are going in the focused stack!
+            return focusStack.mStackId;
+        }
+        if (mBounds != null || mLastNonFullscreenBounds != null) {
+            return FREEFORM_WORKSPACE_STACK_ID;
+        }
+        return FULLSCREEN_WORKSPACE_STACK_ID;
+    }
+
+    /** Returns the bounds that should be used to launch this task. */
+    Rect getLaunchBounds() {
+        if (stack == null
+                || stack.mStackId == HOME_STACK_ID
+                || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+            return null;
+        }
+        return mLastNonFullscreenBounds;
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("userId="); pw.print(userId);
                 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a7cd9ff..a8c8dce 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4727,13 +4727,19 @@
                 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
             }
             if (connect && !isConnected) {
-                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
-                        address, deviceName);
+                final int res = AudioSystem.setDeviceConnectionState(device,
+                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
+                if (res != AudioSystem.AUDIO_STATUS_OK) {
+                    Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
+                            " due to command error " + res );
+                    return false;
+                }
                 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
                 return true;
             } else if (!connect && isConnected) {
-                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                        address, deviceName);
+                AudioSystem.setDeviceConnectionState(device,
+                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
+                // always remove even if disconnection failed
                 mConnectedDevices.remove(deviceKey);
                 return true;
             }
@@ -4866,7 +4872,10 @@
             boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
                             (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
                              ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
-            handleDeviceConnection(state == 1, device, address, deviceName);
+            if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
+                // change of connection state failed, bailout
+                return;
+            }
             if (state != 0) {
                 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index a029b0e..3ea4f2c 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -127,9 +127,7 @@
         IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
             @Override
             public void binderDied() {
-                synchronized (mLock) {
-                    removeCallback(callback);
-                }
+                removeCallback(callback);
             }
         };
         synchronized (mLock) {
@@ -344,6 +342,7 @@
         public final String packageName;
         public final UserHandle userHandle;
 
+        private IMediaProjectionCallback mCallback;
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
         private int mType;
@@ -406,7 +405,8 @@
                     throw new IllegalStateException(
                             "Cannot start already started MediaProjection");
                 }
-                registerCallback(callback);
+                mCallback = callback;
+                registerCallback(mCallback);
                 try {
                     mToken = callback.asBinder();
                     mDeathEater = new IBinder.DeathRecipient() {
@@ -435,8 +435,11 @@
                             + "pid=" + Binder.getCallingPid() + ")");
                     return;
                 }
-                mToken.unlinkToDeath(mDeathEater, 0);
                 stopProjectionLocked(this);
+                mToken.unlinkToDeath(mDeathEater, 0);
+                mToken = null;
+                unregisterCallback(mCallback);
+                mCallback = null;
             }
         }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 31fa5c4..57d7758 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -88,7 +88,6 @@
     private int mUser = UserHandle.USER_OWNER;
     private ZenModeConfig mConfig;
     private AudioManagerInternal mAudioManager;
-    private int mPreviousRingerMode = -1;
     private boolean mEffectsSuppressed;
 
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
@@ -236,7 +235,6 @@
         }
         pw.print(prefix); pw.print("mUser="); pw.println(mUser);
         dump(pw, prefix, "mConfig", mConfig);
-        pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
         pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
         mFiltering.dump(pw, prefix);
         mConditions.dump(pw, prefix);
@@ -357,6 +355,17 @@
         Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
     }
 
+    private int getPreviousRingerModeSetting() {
+        return Global.getInt(mContext.getContentResolver(),
+                Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
+    }
+
+    private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
+        Global.putString(
+                mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
+                previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
+    }
+
     private boolean evaluateZenMode(String reason, boolean setRingerMode) {
         if (DEBUG) Log.d(TAG, "evaluateZenMode");
         final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>();
@@ -430,16 +439,15 @@
             case Global.ZEN_MODE_NO_INTERRUPTIONS:
             case Global.ZEN_MODE_ALARMS:
                 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
-                    mPreviousRingerMode = ringerModeInternal;
+                    setPreviousRingerModeSetting(ringerModeInternal);
                     newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
                 }
                 break;
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
             case Global.ZEN_MODE_OFF:
                 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
-                    newRingerModeInternal = mPreviousRingerMode != -1 ? mPreviousRingerMode
-                            : AudioManager.RINGER_MODE_NORMAL;
-                    mPreviousRingerMode = -1;
+                    newRingerModeInternal = getPreviousRingerModeSetting();
+                    setPreviousRingerModeSetting(null);
                 }
                 break;
         }
@@ -593,7 +601,7 @@
                                 && mZenMode != Global.ZEN_MODE_ALARMS) {
                             newZen = Global.ZEN_MODE_ALARMS;
                         }
-                        mPreviousRingerMode = ringerModeOld;
+                        setPreviousRingerModeSetting(ringerModeOld);
                     }
                     break;
                 case AudioManager.RINGER_MODE_VIBRATE:
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 3227ef8..71a2d59 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -34,6 +34,7 @@
 import android.provider.ContactsContract;
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
+import android.security.Credentials;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -298,6 +299,15 @@
                 grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, userId);
             }
 
+            // CertInstaller
+            Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
+            PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackageLPr(
+                    certInstallerIntent, userId);
+            if (certInstallerPackage != null
+                    && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
+                grantRuntimePermissionsLPw(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
+            }
+
             // Dialer
             if (dialerAppPackageNames == null) {
                 Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6490f10..3b9f402 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15926,16 +15926,27 @@
                         "Cannot move system application");
             }
 
-            if (Objects.equals(ps.volumeUuid, volumeUuid)) {
-                throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Package already moved to " + volumeUuid);
+            if (pkg.applicationInfo.isExternalAsec()) {
+                currentAsec = true;
+                currentVolumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
+            } else if (pkg.applicationInfo.isForwardLocked()) {
+                currentAsec = true;
+                currentVolumeUuid = "forward_locked";
+            } else {
+                currentAsec = false;
+                currentVolumeUuid = ps.volumeUuid;
+
+                final File probe = new File(pkg.codePath);
+                final File probeOat = new File(probe, "oat");
+                if (!probe.isDirectory() || !probeOat.isDirectory()) {
+                    throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+                            "Move only supported for modern cluster style installs");
+                }
             }
 
-            final File probe = new File(pkg.codePath);
-            final File probeOat = new File(probe, "oat");
-            if (!probe.isDirectory() || !probeOat.isDirectory()) {
+            if (Objects.equals(currentVolumeUuid, volumeUuid)) {
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
-                        "Move only supported for modern cluster style installs");
+                        "Package already moved to " + volumeUuid);
             }
 
             if (ps.frozen) {
@@ -15944,9 +15955,6 @@
             }
             ps.frozen = true;
 
-            currentAsec = pkg.applicationInfo.isForwardLocked()
-                    || pkg.applicationInfo.isExternalAsec();
-            currentVolumeUuid = ps.volumeUuid;
             codeFile = new File(pkg.codePath);
             installerPackageName = ps.installerPackageName;
             packageAbiOverride = ps.cpuAbiOverrideString;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 16571ea..454cdcf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5258,9 +5258,11 @@
     }
 
     private boolean shouldDispatchInputWhenNonInteractive() {
-        // Send events to keyguard while the screen is on.
-        if (isKeyguardShowingAndNotOccluded() && mDisplay != null
-                && mDisplay.getState() != Display.STATE_OFF) {
+        if (mDisplay == null || mDisplay.getState() == Display.STATE_OFF) {
+            return false;
+        }
+        // Send events to keyguard while the screen is on and it's showing.
+        if (isKeyguardShowingAndNotOccluded()) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 07fc23f..43f4047 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -579,8 +579,14 @@
     private void clearUserHasAuthenticated(int userId) {
         if (userId == UserHandle.USER_ALL) {
             mUserHasAuthenticated.clear();
+            synchronized (mUserHasAuthenticatedSinceBoot) {
+                mUserHasAuthenticatedSinceBoot.clear();
+            }
         } else {
             mUserHasAuthenticated.put(userId, false);
+            synchronized (mUserHasAuthenticatedSinceBoot) {
+                mUserHasAuthenticatedSinceBoot.put(userId, false);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/FocusedTaskFrame.java b/services/core/java/com/android/server/wm/FocusedTaskFrame.java
deleted file mode 100644
index d8e1095..0000000
--- a/services/core/java/com/android/server/wm/FocusedTaskFrame.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.wm;
-
-import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.util.Slog;
-import android.view.Display;
-import android.view.Surface.OutOfResourcesException;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-
-import com.android.server.wm.WindowStateAnimator.SurfaceTrace;
-
-class FocusedTaskFrame {
-    private static final String TAG = "FocusedTaskFrame";
-    private static final boolean DEBUG = false;
-    private static final int THICKNESS = 2;
-    private static final float ALPHA = 0.3f;
-
-    private final SurfaceControl mSurfaceControl;
-    private final Surface mSurface = new Surface();
-    private final Paint mInnerPaint = new Paint();
-    private final Paint mOuterPaint = new Paint();
-    private final Rect mBounds = new Rect();
-    private final Rect mLastBounds = new Rect();
-    private int mLayer = -1;
-
-    public FocusedTaskFrame(Display display, SurfaceSession session) {
-        SurfaceControl ctrl = null;
-        try {
-            if (DEBUG_SURFACE_TRACE) {
-                ctrl = new SurfaceTrace(session, "FocusedTaskFrame",
-                    1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-            } else {
-                ctrl = new SurfaceControl(session, "FocusedTaskFrame",
-                    1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-            }
-            ctrl.setLayerStack(display.getLayerStack());
-            ctrl.setAlpha(ALPHA);
-            mSurface.copyFrom(ctrl);
-        } catch (OutOfResourcesException e) {
-        }
-        mSurfaceControl = ctrl;
-
-        mInnerPaint.setStyle(Paint.Style.STROKE);
-        mInnerPaint.setStrokeWidth(THICKNESS);
-        mInnerPaint.setColor(Color.WHITE);
-        mOuterPaint.setStyle(Paint.Style.STROKE);
-        mOuterPaint.setStrokeWidth(THICKNESS);
-        mOuterPaint.setColor(Color.BLACK);
-    }
-
-    private void draw() {
-        if (mLastBounds.isEmpty()) {
-            // Currently unset. Set it.
-            mLastBounds.set(mBounds);
-        }
-
-        if (DEBUG) Slog.i(TAG, "draw: mBounds=" + mBounds + " mLastBounds=" + mLastBounds);
-
-        Canvas c = null;
-        try {
-            c = mSurface.lockCanvas(mLastBounds);
-        } catch (IllegalArgumentException e) {
-            Slog.e(TAG, "Unable to lock canvas", e);
-        } catch (Surface.OutOfResourcesException e) {
-            Slog.e(TAG, "Unable to lock canvas", e);
-        }
-        if (c == null) {
-            if (DEBUG) Slog.w(TAG, "Canvas is null...");
-            return;
-        }
-
-        c.drawRect(0, 0, mBounds.width(), mBounds.height(), mOuterPaint);
-        c.drawRect(THICKNESS, THICKNESS, mBounds.width() - THICKNESS, mBounds.height() - THICKNESS,
-                mInnerPaint);
-        if (DEBUG) Slog.w(TAG, "c.width=" + c.getWidth() + " c.height=" + c.getHeight()
-                + " c.clip=" + c .getClipBounds());
-        mSurface.unlockCanvasAndPost(c);
-        mLastBounds.set(mBounds);
-    }
-
-    private void setupSurface(boolean visible) {
-        if (mSurfaceControl == null) {
-            return;
-        }
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setupSurface");
-        SurfaceControl.openTransaction();
-        try {
-            if (visible) {
-                mSurfaceControl.setPosition(mBounds.left, mBounds.top);
-                mSurfaceControl.setSize(mBounds.width(), mBounds.height());
-                mSurfaceControl.show();
-            } else {
-                mSurfaceControl.hide();
-            }
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setupSurface");
-        }
-    }
-
-    void setVisibility(Task task) {
-        if (task == null || task.isFullscreen()) {
-            setupSurface(false);
-        } else {
-            task.getBounds(mBounds);
-            setupSurface(true);
-            if (!mBounds.equals(mLastBounds)) {
-                draw();
-            }
-        }
-    }
-
-    // Note: caller responsible for being inside
-    // Surface.openTransaction() / closeTransaction()
-    void setLayer(int layer) {
-        if (mLayer == layer) {
-            return;
-        }
-        mLayer = layer;
-        mSurfaceControl.setLayer(mLayer);
-    }
-}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 79527b7..3ff5be1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -76,12 +76,13 @@
     // of creating a new object per fullscreen task on a display.
     private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
 
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service) {
+    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
         mOverrideConfig = Configuration.EMPTY;
+        setBounds(bounds);
     }
 
     DisplayContent getDisplayContent() {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index aef99bc..90d2593 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -148,8 +148,7 @@
 
     void updateDisplayInfo() {
         if (mDisplayContent != null) {
-            mDisplayContent.getLogicalDisplayRect(mTmpRect);
-            mAnimationBackgroundSurface.setBounds(mTmpRect);
+            setBounds(mFullscreen ? null : mBounds);
             for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
             }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b9740af..7578256 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -709,8 +709,6 @@
                 mService.scheduleAnimationLocked();
             }
 
-            mService.setFocusedTaskLayer();
-
             if (mService.mWatermark != null) {
                 mService.mWatermark.drawIfNeeded();
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 20e24bb..3d7b499 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -250,11 +250,6 @@
     static final int LAYER_OFFSET_DIM = 1;
 
     /**
-     * FocusedTaskFrame layer is immediately above focused window.
-     */
-    static final int LAYER_OFFSET_FOCUSED_TASK = 1;
-
-    /**
      * Animation thumbnail is as far as possible below the window above
      * the thumbnail (or in other words as far as possible above the window
      * below it).
@@ -445,9 +440,6 @@
     StrictModeFlash mStrictModeFlash;
     CircularDisplayMask mCircularDisplayMask;
     EmulatorDisplayOverlay mEmulatorDisplayOverlay;
-    FocusedTaskFrame mFocusedTaskFrame;
-
-    int mFocusedTaskLayer;
 
     final float[] mTmpFloats = new float[9];
     final Rect mTmpContentRect = new Rect();
@@ -990,8 +982,6 @@
         SurfaceControl.openTransaction();
         try {
             createWatermarkInTransaction();
-            mFocusedTaskFrame = new FocusedTaskFrame(
-                    getDefaultDisplayContentLocked().getDisplay(), mFxSession);
         } finally {
             SurfaceControl.closeTransaction();
         }
@@ -3697,24 +3687,26 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken) {
+    private Task createTaskLocked(
+            int taskId, int stackId, int userId, AppWindowToken atoken, Rect bounds) {
         if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
-                + " atoken=" + atoken);
+                + " atoken=" + atoken + " bounds=" + bounds);
         final TaskStack stack = mStackIdToStack.get(stackId);
         if (stack == null) {
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(taskId, stack, userId, this);
+        Task task = new Task(taskId, stack, userId, this, bounds);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
         return task;
     }
 
     @Override
-    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    public Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
-            int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
+            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
+            Rect taskBounds) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3738,7 +3730,7 @@
             AppWindowToken atoken = findAppWindowToken(token.asBinder());
             if (atoken != null) {
                 Slog.w(TAG, "Attempted to add existing app token: " + token);
-                return;
+                return null;
             }
             atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
@@ -3752,8 +3744,10 @@
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
             Task task = mTaskIdToTask.get(taskId);
+            Configuration outConfig = null;
             if (task == null) {
-                task = createTaskLocked(taskId, stackId, userId, atoken);
+                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds);
+                outConfig = task.mOverrideConfig;
             }
             task.addAppToken(addPos, atoken);
 
@@ -3763,12 +3757,12 @@
             atoken.hidden = true;
             atoken.hiddenRequested = true;
 
-            //dump();
+            return outConfig;
         }
     }
 
     @Override
-    public void setAppTask(IBinder token, int taskId) {
+    public Configuration setAppTask(IBinder token, int taskId, Rect taskBounds) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3778,17 +3772,20 @@
             final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
-                return;
+                return null;
             }
             final Task oldTask = atoken.mTask;
             oldTask.removeAppToken(atoken);
 
             Task newTask = mTaskIdToTask.get(taskId);
+            Configuration outConfig = null;
             if (newTask == null) {
-                newTask =
-                        createTaskLocked(taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken);
+                newTask = createTaskLocked(
+                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds);
+                outConfig = newTask.mOverrideConfig;
             }
             newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
+            return outConfig;
         }
     }
 
@@ -4074,34 +4071,14 @@
         }
     }
 
-    /** Call while in a Surface transaction. */
-    void setFocusedTaskLayer() {
-        mFocusedTaskLayer = 0;
+    void setFocusTaskRegion() {
         if (mFocusedApp != null) {
-            final WindowList windows = mFocusedApp.allAppWindows;
-            for (int i = windows.size() - 1; i >= 0; --i) {
-                final WindowState win = windows.get(i);
-                final int animLayer = win.mWinAnimator.mAnimLayer;
-                if (win.mAttachedWindow == null && win.isVisibleLw() &&
-                        animLayer > mFocusedTaskLayer) {
-                    mFocusedTaskLayer = animLayer + LAYER_OFFSET_FOCUSED_TASK;
-                }
-            }
-        }
-        if (DEBUG_LAYERS) Slog.v(TAG, "Setting FocusedTaskFrame to layer=" + mFocusedTaskLayer);
-        mFocusedTaskFrame.setLayer(mFocusedTaskLayer);
-    }
-
-    void setFocusedTaskFrame() {
-        Task task = null;
-        if (mFocusedApp != null) {
-            task = mFocusedApp.mTask;
+            final Task task = mFocusedApp.mTask;
             final DisplayContent displayContent = task.getDisplayContent();
             if (displayContent != null) {
                 displayContent.setTouchExcludeRegion(task);
             }
         }
-        mFocusedTaskFrame.setVisibility(task);
     }
 
     @Override
@@ -4129,15 +4106,7 @@
             if (changed) {
                 mFocusedApp = newFocus;
                 mInputMonitor.setFocusedAppLw(newFocus);
-                setFocusedTaskFrame();
-                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedApp");
-                SurfaceControl.openTransaction();
-                try {
-                    setFocusedTaskLayer();
-                } finally {
-                    SurfaceControl.closeTransaction();
-                    if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedApp");
-                }
+                setFocusTaskRegion();
             }
 
             if (moveFocusNow && changed) {
@@ -10409,7 +10378,7 @@
         if (updateInputWindowsNeeded) {
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
-        setFocusedTaskFrame();
+        setFocusTaskRegion();
 
         // Check to see if we are now in a state where the screen should
         // be enabled, because the window obscured flags have changed.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f7bf6e4..4061149 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -859,12 +859,9 @@
     Task getTask() {
         AppWindowToken wtoken = mAppToken == null ? mService.mFocusedApp : mAppToken;
         if (wtoken == null) {
-            Slog.e(TAG, "getTask: " + this + " null wtoken " + " Callers=" + Debug.getCallers(5));
             return null;
         }
         final Task task = wtoken.mTask;
-        if (task == null) Slog.e(TAG, "getStack: " + this + " couldn't find task for " + wtoken
-                    + " Callers=" + Debug.getCallers(5));
         return task;
     }
 
@@ -874,7 +871,6 @@
             if (task.mStack != null) {
                 return task.mStack;
             }
-            Slog.e(TAG, "getStack: mStack null for task=" + task);
         }
         return mDisplayContent.getHomeStack();
     }
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 19d29f3..696f106 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -937,6 +937,19 @@
     }
 
     private void tryNetworkFactoryRequests(int capability) throws Exception {
+        // Verify NOT_RESTRICTED is set appropriately
+        final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
+                .build().networkCapabilities;
+        if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
+                capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
+                capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
+                capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP ||
+                capability == NET_CAPABILITY_TRUSTED || capability == NET_CAPABILITY_NOT_VPN) {
+            assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        } else {
+            assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        }
+
         NetworkCapabilities filter = new NetworkCapabilities();
         filter.addCapability(capability);
         final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 04d6d98..1788e88 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -48,6 +48,7 @@
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
@@ -225,6 +226,7 @@
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && structureEnabled) {
                     try {
+                        MetricsLogger.count(mContext, "assist_with_context", 1);
                         if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
                                 mAssistReceiver, activityToken)) {
                             needDisclosure = true;
@@ -249,6 +251,7 @@
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && screenshotEnabled) {
                     try {
+                        MetricsLogger.count(mContext, "assist_with_screen", 1);
                         needDisclosure = true;
                         mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
                     } catch (RemoteException e) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 49f738b..d91fa90 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1019,6 +1019,7 @@
                 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
             mCannedTextResponses =
                     Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
+            cannedTextResponsesChanged = true;
         }
 
         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 706dcfb..7b277c5 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -253,12 +253,6 @@
     //**********************************************************************************************
 
     /**
-     * TODO: Remove this -- retained so the build won't break.  However, future work will remove it.
-     * @hide
-     */
-    public static final String EXTRA_CALL_HISTORY_INFO = "android.telecom.EXTRA_CALL_HISTORY_INFO";
-
-    /**
      * Connection extra key used to store the last forwarded number associated with the current
      * connection.  Used to communicate to the user interface that the connection was forwarded via
      * the specified number.
@@ -1594,7 +1588,7 @@
         return mUnmodifiableConferenceables;
     }
 
-    /*
+    /**
      * @hide
      */
     public final void setConnectionService(ConnectionService connectionService) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e9c41a1..b5e4342 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -259,6 +259,14 @@
             = "carrier_allow_turnoff_ims_bool";
 
     /**
+     * Flag specifying whether IMS instant lettering is available for the carrier.  {@code True} if
+     * instant lettering is available for the carrier, {@code false} otherwise.
+     * @hide
+     */
+    public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL =
+            "carrier_instant_lettering_available_bool";
+
+    /**
      * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
      * this is the value that should be used instead. A configuration value of
      * RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
@@ -393,6 +401,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
+        sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL, false);
         sDefaults.putBoolean(KEY_DTMF_TYPE_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a8066d8..88612e9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2060,6 +2060,8 @@
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *   OR
+     *   {@link android.Manifest.permission#READ_SMS}
      * <p>
      * The default SMS app can also use this.
      */
@@ -2073,6 +2075,8 @@
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *   OR
+     *   {@link android.Manifest.permission#READ_SMS}
      * <p>
      * The default SMS app can also use this.
      *
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index e44969d..6177784 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
         }
         
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -103,7 +103,7 @@
         }
         
         try {
-            mWm.setAppTask(null, 0);
+            mWm.setAppTask(null, 0, null);
             fail("IWindowManager.setAppGroupId did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 2e515fb..6a61090 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -239,15 +239,12 @@
     public int getInt(int index, int defValue) {
         String s = getString(index);
         try {
-            if (s != null) {
-                return convertValueToInt(s, defValue);
-            }
+            return convertValueToInt(s, defValue);
         } catch (NumberFormatException e) {
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                     String.format("\"%1$s\" in attribute \"%2$s\" is not a valid integer",
                             s, mNames[index]),
                     null);
-            return defValue;
         }
         return defValue;
     }
@@ -949,7 +946,7 @@
      * "XXXXXXXX" > 80000000.
      */
     private static int convertValueToInt(@Nullable String charSeq, int defValue) {
-        if (null == charSeq)
+        if (null == charSeq || charSeq.isEmpty())
             return defValue;
 
         int sign = 1;
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 82012c1..62859ec 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.graphics.Point;
+import android.graphics.Rect;
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -72,11 +73,11 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
-            boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10)
-            throws RemoteException {
+    public Configuration addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
+            boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
+            Rect arg11) throws RemoteException {
         // TODO Auto-generated method stub
-
+        return Configuration.EMPTY;
     }
 
     @Override
@@ -307,9 +308,9 @@
     }
 
     @Override
-    public void setAppTask(IBinder arg0, int arg1) throws RemoteException {
+    public Configuration setAppTask(IBinder arg0, int arg1, Rect arg2) throws RemoteException {
         // TODO Auto-generated method stub
-
+        return Configuration.EMPTY;
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
index c72c979..cbd0415 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
@@ -131,6 +131,7 @@
         HardwareConfig hwConfig = getParams().getHardwareConfig();
         Density density = hwConfig.getDensity();
         boolean isRtl = Bridge.isLocaleRtl(getParams().getLocale());
+        setLayoutDirection(isRtl? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR);
 
         NavigationBar navBar = null;
         if (mBuilder.hasNavBar()) {
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index cc1e976..8a20012 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -363,11 +363,10 @@
     }
 
     /** {@hide} */
-    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
+    public ScanResult(String Ssid, String BSSID, String caps, int level, int frequency,
             long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
             boolean is80211McRTTResponder) {
-        this.wifiSsid = wifiSsid;
-        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
+        this.SSID = Ssid;
         this.BSSID = BSSID;
         this.capabilities = caps;
         this.level = level;
@@ -385,6 +384,15 @@
         }
     }
 
+    /** {@hide} */
+    public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, String caps, int level,
+                  int frequency, long tsf, int distCm, int distSdCm, int channelWidth,
+                  int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) {
+        this(Ssid, BSSID, caps,level, frequency, tsf, distCm, distSdCm, channelWidth, centerFreq0,
+                centerFreq1, is80211McRTTResponder);
+        this.wifiSsid = wifiSsid;
+    }
+
     /** copy constructor {@hide} */
     public ScanResult(ScanResult source) {
         if (source != null) {
@@ -469,6 +477,7 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeString(SSID);
         dest.writeString(BSSID);
         dest.writeString(capabilities);
         dest.writeInt(level);
@@ -512,6 +521,7 @@
                 }
                 ScanResult sr = new ScanResult(
                     wifiSsid,
+                    in.readString(),                    /* SSID  */
                     in.readString(),                    /* BSSID */
                     in.readString(),                    /* capabilities */
                     in.readInt(),                       /* level */
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index a3dc077..a65f250 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -255,9 +255,7 @@
             mResults = new ScanResult[s.mResults.length];
             for (int i = 0; i < s.mResults.length; i++) {
                 ScanResult result = s.mResults[i];
-                WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(result.SSID);
                 ScanResult newResult = new ScanResult(result);
-                newResult.wifiSsid = wifiSsid;
                 mResults[i] = newResult;
             }
         }