Merge "More file-based encryption work."
diff --git a/api/current.txt b/api/current.txt
index 1a7139c..e17bf28 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2732,6 +2732,7 @@
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
@@ -2796,6 +2797,7 @@
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2812,6 +2814,8 @@
     field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
+    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
+    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
     field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -3773,6 +3777,8 @@
   }
 
   public class ActivityOptions {
+    method public android.graphics.Rect getLaunchBounds();
+    method public boolean hasLaunchBounds();
     method public static android.app.ActivityOptions makeBasic();
     method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -3782,6 +3788,7 @@
     method public static android.app.ActivityOptions makeTaskLaunchBehind();
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
     field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
diff --git a/api/system-current.txt b/api/system-current.txt
index f2784410..d8b9b6f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2831,6 +2831,7 @@
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
@@ -2895,6 +2896,7 @@
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2911,6 +2913,8 @@
     field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
+    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
+    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
     field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -3882,6 +3886,8 @@
   }
 
   public class ActivityOptions {
+    method public android.graphics.Rect getLaunchBounds();
+    method public boolean hasLaunchBounds();
     method public static android.app.ActivityOptions makeBasic();
     method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
@@ -3891,6 +3897,7 @@
     method public static android.app.ActivityOptions makeTaskLaunchBehind();
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
     field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 9c401c7f..185ceb4 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -116,6 +116,25 @@
      */
     public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
 
+    /**
+     * Bundle key used for the {@link String} account type in session bundle.
+     * This is used in the default implementation of
+     * {@link #startAddAccountSession}. TODO: and startUpdateCredentialsSession.
+     */
+    private static final String KEY_AUTH_TOKEN_TYPE = "android.accounts.KEY_AUTH_TOKEN_TYPE";
+    /**
+     * Bundle key used for the {@link String} array of required features in
+     * session bundle. This is used in the default implementation of
+     * {@link #startAddAccountSession}. TODO: and startUpdateCredentialsSession.
+     */
+    private static final String KEY_REQUIRED_FEATURES = "android.accounts.AbstractAccountAuthenticator.KEY_REQUIRED_FEATURES";
+    /**
+     * Bundle key used for the {@link Bundle} options in session bundle. This is
+     * used in default implementation of {@link #startAddAccountSession}. TODO:
+     * and startUpdateCredentialsSession.
+     */
+    private static final String KEY_OPTIONS = "android.accounts.AbstractAccountAuthenticator.KEY_OPTIONS";
+
     private final Context mContext;
 
     public AbstractAccountAuthenticator(Context context) {
@@ -336,6 +355,36 @@
                 handleException(response, "addAccountFromCredentials", account.toString(), e);
             }
         }
+
+        @Override
+        public void startAddAccountSession(IAccountAuthenticatorResponse response,
+                String accountType, String authTokenType, String[] features, Bundle options)
+                throws RemoteException {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG,
+                        "startAddAccountSession: accountType " + accountType
+                        + ", authTokenType " + authTokenType
+                        + ", features " + (features == null ? "[]" : Arrays.toString(features)));
+            }
+            checkBinderPermission();
+            try {
+                final Bundle result = AbstractAccountAuthenticator.this.startAddAccountSession(
+                        new AccountAuthenticatorResponse(response), accountType, authTokenType,
+                        features, options);
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
+                    Log.v(TAG, "startAddAccountSession: result "
+                            + AccountManager.sanitizeResult(result));
+                }
+                if (result != null) {
+                    response.onResult(result);
+                }
+            } catch (Exception e) {
+                handleException(response, "startAddAccountSession", accountType, e);
+            }
+        }
     }
 
     private void handleException(IAccountAuthenticatorResponse response, String method,
@@ -603,4 +652,52 @@
         }).start();
         return null;
     }
+
+    /**
+     * Starts the add account session to authenticate user to an account of the
+     * specified accountType.
+     *
+     * @param response to send the result back to the AccountManager, will never
+     *            be null
+     * @param accountType the type of account to authenticate with, will never
+     *            be null
+     * @param authTokenType the type of auth token to retrieve after
+     *            authenticating with the account, may be null
+     * @param requiredFeatures a String array of authenticator-specific features
+     *            that the account authenticated with must support, may be null
+     * @param options a Bundle of authenticator-specific options, may be null
+     * @return a Bundle result or null if the result is to be returned via the
+     *         response. The result will contain either:
+     *         <ul>
+     *         <li>{@link AccountManager#KEY_INTENT}, or
+     *         <li>{@link AccountManager#KEY_ACCOUNT_SESSION_BUNDLE} for adding
+     *         the account to device later, and if account is authenticated,
+     *         optional {@link AccountManager#KEY_PASSWORD} and
+     *         {@link AccountManager#KEY_ACCOUNT_STATUS_TOKEN} for checking the
+     *         status of the account, or
+     *         <li>{@link AccountManager#KEY_ERROR_CODE} and
+     *         {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
+     *         </ul>
+     * @throws NetworkErrorException if the authenticator could not honor the
+     *             request due to a network error
+     */
+    public Bundle startAddAccountSession(final AccountAuthenticatorResponse response,
+            final String accountType, final String authTokenType, final String[] requiredFeatures,
+            final Bundle options)
+            throws NetworkErrorException {
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                Bundle sessionBundle = new Bundle();
+                sessionBundle.putString(KEY_AUTH_TOKEN_TYPE, authTokenType);
+                sessionBundle.putStringArray(KEY_REQUIRED_FEATURES, requiredFeatures);
+                sessionBundle.putBundle(KEY_OPTIONS, options);
+                Bundle result = new Bundle();
+                result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+                response.onResult(result);
+            }
+
+        }).start();
+        return null;
+    }
 }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 0a7568a..42e5e2a 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -240,6 +240,20 @@
      */
     public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
 
+    /**
+     * Bundle key used for a {@link Bundle} in result from
+     * {@link #startAddAccountSession} and friends which returns session data
+     * for installing an account later.
+     */
+    public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
+
+    /**
+     * Bundle key used for the {@link String} account status token in result
+     * from {@link #startAddAccountSession} and friends which returns
+     * information about a particular account.
+     */
+    public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
+
     public static final String ACTION_AUTHENTICATOR_INTENT =
             "android.accounts.AccountAuthenticator";
     public static final String AUTHENTICATOR_META_DATA_NAME =
@@ -2590,4 +2604,84 @@
             }
         }
     }
+
+    /**
+     * Asks the user to authenticate with an account of a specified type. The
+     * authenticator for this account type processes this request with the
+     * appropriate user interface. If the user does elect to authenticate with a
+     * new account, a bundle of session data for installing the account later is
+     * returned with optional account password and account status token.
+     * <p>
+     * This method may be called from any thread, but the returned
+     * {@link AccountManagerFuture} must not be used on the main thread.
+     * <p>
+     * <p>
+     * <b>NOTE:</b> The account will not be installed to the device by calling
+     * this api alone.
+     *
+     * @param accountType The type of account to add; must not be null
+     * @param authTokenType The type of auth token (see {@link #getAuthToken})
+     *            this account will need to be able to generate, null for none
+     * @param requiredFeatures The features (see {@link #hasFeatures}) this
+     *            account must have, null for none
+     * @param options Authenticator-specific options for the request, may be
+     *            null or empty
+     * @param activity The {@link Activity} context to use for launching a new
+     *            authenticator-defined sub-Activity to prompt the user to
+     *            create an account; used only to call startActivity(); if null,
+     *            the prompt will not be launched directly, but the necessary
+     *            {@link Intent} will be returned to the caller instead
+     * @param callback Callback to invoke when the request completes, null for
+     *            no callback
+     * @param handler {@link Handler} identifying the callback thread, null for
+     *            the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+     *         these fields if activity was specified and user was authenticated
+     *         with an account:
+     *         <ul>
+     *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
+     *         adding the the to the device later.
+     *         <li>{@link #KEY_PASSWORD} - optional, the password or password
+     *         hash of the account.
+     *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
+     *         status of the account
+     *         </ul>
+     *         If no activity was specified, the returned Bundle contains only
+     *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
+     *         actual account creation process. If authenticator doesn't support
+     *         this method, the returned Bundle contains only
+     *         {@link #KEY_ACCOUNT_SESSION_BUNDLE} with encrypted
+     *         {@code options} needed to add account later. If an error
+     *         occurred, {@link AccountManagerFuture#getResult()} throws:
+     *         <ul>
+     *         <li>{@link AuthenticatorException} if no authenticator was
+     *         registered for this account type or the authenticator failed to
+     *         respond
+     *         <li>{@link OperationCanceledException} if the operation was
+     *         canceled for any reason, including the user canceling the
+     *         creation process or adding accounts (of this type) has been
+     *         disabled by policy
+     *         <li>{@link IOException} if the authenticator experienced an I/O
+     *         problem creating a new account, usually because of network
+     *         trouble
+     *         </ul>
+     */
+    public AccountManagerFuture<Bundle> startAddAccountSession(final String accountType,
+            final String authTokenType, final String[] requiredFeatures, final Bundle options,
+            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        final Bundle optionsIn = new Bundle();
+        if (options != null) {
+            optionsIn.putAll(options);
+        }
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
+        return new AmsTask(activity, handler, callback) {
+            @Override
+            public void doWork() throws RemoteException {
+                mService.startAddAccountSession(mResponse, accountType, authTokenType,
+                        requiredFeatures, activity != null, optionsIn);
+            }
+        }.start();
+    }
 }
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 58612da..b326070 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -83,4 +83,11 @@
      */
     void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,
             in Bundle accountCredentials);
+
+    /**
+     * Starts the add account session by prompting the user for account information
+     * and return a Bundle containing data to finish the session later.
+     */
+    void startAddAccountSession(in IAccountAuthenticatorResponse response, String accountType,
+        String authTokenType, in String[] requiredFeatures, in Bundle options);
 }
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 0d95db1..5de311e 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -83,4 +83,9 @@
     String getPreviousName(in Account account);
     boolean renameSharedAccountAsUser(in Account accountToRename, String newName, int userId);
 
+    /* Add account in two steps. */
+    void startAddAccountSession(in IAccountManagerResponse response, String accountType,
+        String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
+        in Bundle options);
+
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 00bba2d..f7aee75 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -528,6 +528,15 @@
             return stackId == FULLSCREEN_WORKSPACE_STACK_ID
                     || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID;
         }
+
+        /**
+         * Returns true if animation specs should be constructed for app transition that moves
+         * the task to the specified stack.
+         */
+        public static boolean useAnimationSpecForAppTransition(int stackId) {
+            return stackId == FREEFORM_WORKSPACE_STACK_ID
+                    || stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
+        }
     }
 
     /**
@@ -884,7 +893,7 @@
             if (mIcon != null) {
                 return mIcon;
             }
-            return loadTaskDescriptionIcon(mIconFilename);
+            return loadTaskDescriptionIcon(mIconFilename, UserHandle.myUserId());
         }
 
         /** @hide */
@@ -898,11 +907,11 @@
         }
 
         /** @hide */
-        public static Bitmap loadTaskDescriptionIcon(String iconFilename) {
+        public static Bitmap loadTaskDescriptionIcon(String iconFilename, int userId) {
             if (iconFilename != null) {
                 try {
                     return ActivityManagerNative.getDefault().
-                            getTaskDescriptionIcon(iconFilename);
+                            getTaskDescriptionIcon(iconFilename, userId);
                 } catch (RemoteException e) {
                 }
             }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 73b81cd..0b7b6fc 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2500,7 +2500,8 @@
         case GET_TASK_DESCRIPTION_ICON_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String filename = data.readString();
-            Bitmap icon = getTaskDescriptionIcon(filename);
+            int userId = data.readInt();
+            Bitmap icon = getTaskDescriptionIcon(filename, userId);
             reply.writeNoException();
             if (icon == null) {
                 reply.writeInt(0);
@@ -6022,11 +6023,12 @@
     }
 
     @Override
-    public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException {
+    public Bitmap getTaskDescriptionIcon(String filename, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(filename);
+        data.writeInt(userId);
         mRemote.transact(GET_TASK_DESCRIPTION_ICON_TRANSACTION, data, reply, 0);
         reply.readException();
         final Bitmap icon = reply.readInt() == 0 ? null : Bitmap.CREATOR.createFromParcel(reply);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 57900aa..cee1aa5 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -64,11 +64,13 @@
     public static final String KEY_PACKAGE_NAME = "android:activity.packageName";
 
     /**
-     * The bounds that the activity should be started in. Set to null explicitly
-     * for full screen. If the key is not found, previous bounds will be preserved.
+     * The bounds (window size) that the activity should be launched in. Set to null explicitly for
+     * full screen. If the key is not found, previous bounds will be preserved.
+     * NOTE: This value is ignored on devices that don't have
+     * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled.
      * @hide
      */
-    public static final String KEY_BOUNDS = "android:activity.bounds";
+    public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
 
     /**
      * Type of animation that arguments specify.
@@ -193,8 +195,8 @@
     public static final int ANIM_CLIP_REVEAL = 11;
 
     private String mPackageName;
-    private boolean mHasBounds;
-    private Rect mBounds;
+    private boolean mHasLaunchBounds;
+    private Rect mLaunchBounds;
     private int mAnimationType = ANIM_NONE;
     private int mCustomEnterResId;
     private int mCustomExitResId;
@@ -705,9 +707,9 @@
         } catch (RuntimeException e) {
             Slog.w(TAG, e);
         }
-        mHasBounds = opts.containsKey(KEY_BOUNDS);
-        if (mHasBounds) {
-            mBounds = opts.getParcelable(KEY_BOUNDS);
+        mHasLaunchBounds = opts.containsKey(KEY_LAUNCH_BOUNDS);
+        if (mHasLaunchBounds) {
+            mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);
         }
         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
         switch (mAnimationType) {
@@ -766,10 +768,15 @@
         }
     }
 
-    /** @hide */
-    public ActivityOptions setBounds(Rect bounds) {
-        mHasBounds = true;
-        mBounds = bounds;
+    /**
+     * Sets the bounds (window size) that the activity should be launched in. Set to null explicitly
+     * for full screen.
+     * NOTE: This value is ignored on devices that don't have
+     * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled.
+     */
+    public ActivityOptions setLaunchBounds(Rect launchBounds) {
+        mHasLaunchBounds = true;
+        mLaunchBounds = launchBounds;
         return this;
     }
 
@@ -778,14 +785,12 @@
         return mPackageName;
     }
 
-    /** @hide */
-    public boolean hasBounds() {
-        return mHasBounds;
+    public boolean hasLaunchBounds() {
+        return mHasLaunchBounds;
     }
 
-    /** @hide */
-    public Rect getBounds(){
-        return mBounds;
+    public Rect getLaunchBounds(){
+        return mLaunchBounds;
     }
 
     /** @hide */
@@ -997,8 +1002,8 @@
         if (mPackageName != null) {
             b.putString(KEY_PACKAGE_NAME, mPackageName);
         }
-        if (mHasBounds) {
-            b.putParcelable(KEY_BOUNDS, mBounds);
+        if (mHasLaunchBounds) {
+            b.putParcelable(KEY_LAUNCH_BOUNDS, mLaunchBounds);
         }
         b.putInt(KEY_ANIM_TYPE, mAnimationType);
         if (mUsageTimeReport != null) {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index c0cc566..20f3495 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -575,14 +575,20 @@
         setGhostVisibility(View.INVISIBLE);
         mHasStopped = true;
         mIsCanceled = true;
+        clearState();
+        return super.cancelPendingTransitions();
+    }
+
+    @Override
+    protected void clearState() {
+        mSharedElementsBundle = null;
+        mEnterViewsTransition = null;
         mResultReceiver = null;
         if (mBackgroundAnimator != null) {
             mBackgroundAnimator.cancel();
             mBackgroundAnimator = null;
         }
-        mActivity = null;
-        clearState();
-        return super.cancelPendingTransitions();
+        super.clearState();
     }
 
     private void makeOpaque() {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 4b670cd..e93b40e 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -470,6 +470,11 @@
             mActivity = null;
         }
         // Clear the state so that we can't hold any references accidentally and leak memory.
+        clearState();
+    }
+
+    @Override
+    protected void clearState() {
         mHandler = null;
         mSharedElementBundle = null;
         if (mBackgroundAnimator != null) {
@@ -477,7 +482,7 @@
             mBackgroundAnimator = null;
         }
         mExitSharedElementBundle = null;
-        clearState();
+        super.clearState();
     }
 
     @Override
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3027e9c..db4f5c1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -498,7 +498,7 @@
     public void resizeTask(int taskId, Rect bounds, int resizeMode) throws RemoteException;
 
     public Rect getTaskBounds(int taskId) throws RemoteException;
-    public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
+    public Bitmap getTaskDescriptionIcon(String filename, int userId) throws RemoteException;
 
     public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
             throws RemoteException;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 30232da..84ddd9f 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -50,9 +50,6 @@
     void setPackagePriority(String pkg, int uid, int priority);
     int getPackagePriority(String pkg, int uid);
 
-    void setPackagePeekable(String pkg, int uid, boolean peekable);
-    boolean getPackagePeekable(String pkg, int uid);
-
     void setPackageVisibilityOverride(String pkg, int uid, int visibility);
     int getPackageVisibilityOverride(String pkg, int uid);
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 390c280..4e6548b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -838,13 +838,6 @@
     public static final String EXTRA_PEOPLE = "android.people";
 
     /**
-     * {@link #extras} key: used to provide hints about the appropriateness of
-     * displaying this notification as a heads-up notification.
-     * @hide
-     */
-    public static final String EXTRA_AS_HEADS_UP = "headsup";
-
-    /**
      * Allow certain system-generated notifications to appear before the device is provisioned.
      * Only available to notifications coming from the android package.
      * @hide
@@ -887,32 +880,6 @@
      */
     public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";
 
-    /**
-     * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be
-     * displayed in the heads up space.
-     *
-     * <p>
-     * If this notification has a {@link #fullScreenIntent}, then it will always launch the
-     * full-screen intent when posted.
-     * </p>
-     * @hide
-     */
-    public static final int HEADS_UP_NEVER = 0;
-
-    /**
-     * Default value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification may be
-     * displayed as a heads up.
-     * @hide
-     */
-    public static final int HEADS_UP_ALLOWED = 1;
-
-    /**
-     * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification is a
-     * good candidate for display as a heads up.
-     * @hide
-     */
-    public static final int HEADS_UP_REQUESTED = 2;
-
     private Icon mSmallIcon;
     private Icon mLargeIcon;
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 9428f44..19a98f3 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -540,6 +540,13 @@
         void deactivate() {
             mActive = false;
         }
+
+        @Override
+        public String toString() {
+            return "ControlledInputConnectionWrapper{mActive=" + mActive
+                    + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
+                    + "}";
+        }
     }
     
     final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 65e8058..bd41c5d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -580,7 +580,8 @@
     char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
     char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
     char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];
-    char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
+    char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
+    char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
     char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
@@ -684,7 +685,8 @@
      * JIT related options.
      */
     parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
-    parseRuntimeOption("dalvik.vm.jitcodecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
+    parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");
+    parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");
     parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
 
     property_get("ro.config.low_ram", propBuf, "");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3f1be45..73c7487 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 
 #include <list>
+#include <sstream>
 #include <string>
 
 #include <fcntl.h>
@@ -74,8 +75,10 @@
   MOUNT_EXTERNAL_WRITE = 3,
 };
 
-static void RuntimeAbort(JNIEnv* env) {
-  env->FatalError("RuntimeAbort");
+static void RuntimeAbort(JNIEnv* env, int line, const char* msg) {
+  std::ostringstream oss;
+  oss << __FILE__ << ":" << line << ": " << msg;
+  env->FatalError(oss.str().c_str());
 }
 
 // This signal handler is for zygote mode, since the zygote must reap its children
@@ -169,12 +172,11 @@
 
   ScopedIntArrayRO gids(env, javaGids);
   if (gids.get() == NULL) {
-      RuntimeAbort(env);
+    RuntimeAbort(env, __LINE__, "Getting gids int array failed");
   }
   int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
   if (rc == -1) {
-    ALOGE("setgroups failed");
-    RuntimeAbort(env);
+    RuntimeAbort(env, __LINE__, "setgroups failed");
   }
 }
 
@@ -194,8 +196,7 @@
     ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
     ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
     if (javaRlimit.size() != 3) {
-      ALOGE("rlimits array must have a second dimension of size 3");
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "rlimits array must have a second dimension of size 3");
     }
 
     rlim.rlim_cur = javaRlimit[1];
@@ -205,7 +206,7 @@
     if (rc == -1) {
       ALOGE("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
             rlim.rlim_max);
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "setrlimit failed");
     }
   }
 }
@@ -216,8 +217,7 @@
 static void EnableKeepCapabilities(JNIEnv* env) {
   int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
   if (rc == -1) {
-    ALOGE("prctl(PR_SET_KEEPCAPS) failed");
-    RuntimeAbort(env);
+    RuntimeAbort(env, __LINE__, "prctl(PR_SET_KEEPCAPS) failed");
   }
 }
 
@@ -229,8 +229,7 @@
         ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
               "your kernel is compiled with file capabilities support");
       } else {
-        ALOGE("prctl(PR_CAPBSET_DROP) failed");
-        RuntimeAbort(env);
+        RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
       }
     }
   }
@@ -251,7 +250,7 @@
 
   if (capset(&capheader, &capdata[0]) == -1) {
     ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective);
-    RuntimeAbort(env);
+    RuntimeAbort(env, __LINE__, "capset failed");
   }
 }
 
@@ -259,7 +258,7 @@
   errno = -set_sched_policy(0, SP_DEFAULT);
   if (errno != 0) {
     ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
-    RuntimeAbort(env);
+    RuntimeAbort(env, __LINE__, "set_sched_policy(0, SP_DEFAULT) failed");
   }
 }
 
@@ -370,8 +369,7 @@
   jsize count = env->GetArrayLength(fdsToClose);
   ScopedIntArrayRO ar(env, fdsToClose);
   if (ar.get() == NULL) {
-      ALOGE("Bad fd array");
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "Bad fd array");
   }
   jsize i;
   int devnull;
@@ -379,13 +377,13 @@
     devnull = open("/dev/null", O_RDWR);
     if (devnull < 0) {
       ALOGE("Failed to open /dev/null: %s", strerror(errno));
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "Failed to open /dev/null");
       continue;
     }
     ALOGV("Switching descriptor %d to /dev/null: %s", ar[i], strerror(errno));
     if (dup2(devnull, ar[i]) < 0) {
       ALOGE("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "Failed dup2()");
     }
     close(devnull);
   }
@@ -493,8 +491,7 @@
         // FUSE hasn't been created yet by init.
         // In either case, continue without external storage.
       } else {
-        ALOGE("Cannot continue without emulated storage");
-        RuntimeAbort(env);
+        RuntimeAbort(env, __LINE__, "Cannot continue without emulated storage");
       }
     }
 
@@ -522,13 +519,13 @@
     int rc = setresgid(gid, gid, gid);
     if (rc == -1) {
       ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "setresgid failed");
     }
 
     rc = setresuid(uid, uid, uid);
     if (rc == -1) {
       ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "setresuid failed");
     }
 
     if (NeedsNoRandomizeWorkaround()) {
@@ -550,8 +547,7 @@
         se_info = new ScopedUtfChars(env, java_se_info);
         se_info_c_str = se_info->c_str();
         if (se_info_c_str == NULL) {
-          ALOGE("se_info_c_str == NULL");
-          RuntimeAbort(env);
+          RuntimeAbort(env, __LINE__, "se_info_c_str == NULL");
         }
     }
     const char* se_name_c_str = NULL;
@@ -560,15 +556,14 @@
         se_name = new ScopedUtfChars(env, java_se_name);
         se_name_c_str = se_name->c_str();
         if (se_name_c_str == NULL) {
-          ALOGE("se_name_c_str == NULL");
-          RuntimeAbort(env);
+          RuntimeAbort(env, __LINE__, "se_name_c_str == NULL");
         }
     }
     rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
     if (rc == -1) {
       ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
             is_system_server, se_info_c_str, se_name_c_str);
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "selinux_android_setcontext failed");
     }
 
     // Make it easier to debug audit logs by setting the main thread's name to the
@@ -588,8 +583,7 @@
     env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                               is_system_server ? NULL : instructionSet);
     if (env->ExceptionCheck()) {
-      ALOGE("Error calling post fork hooks.");
-      RuntimeAbort(env);
+      RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
     }
   } else if (pid > 0) {
     // the parent process
@@ -641,7 +635,7 @@
       int status;
       if (waitpid(pid, &status, WNOHANG) == pid) {
           ALOGE("System server process %d has died. Restarting Zygote!", pid);
-          RuntimeAbort(env);
+          RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
       }
   }
   return pid;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index a50c945..0ee877e 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1424,7 +1424,7 @@
         }
     }
 
-    static int resolveDensity(@NonNull Resources r, int parentDensity) {
+    static int resolveDensity(@Nullable Resources r, int parentDensity) {
         final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi;
         return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
     }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index f961a59..f630055e 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -231,6 +231,9 @@
     private int mDpiScaledHeight = 0;
     private Insets mDpiScaledInsets = Insets.NONE;
 
+    /** Whether DPI-scaled width, height, and insets need to be updated. */
+    private boolean mDpiScaledDirty = true;
+
     // Temp variable, only for saving "new" operation at the draw() time.
     private final float[] mTmpFloats = new float[9];
     private final Matrix mTmpMatrix = new Matrix();
@@ -259,9 +262,13 @@
      *            displayed, or {@code null} to use the constant state defaults
      */
     private void updateLocalState(Resources res) {
-        mTargetDensity = Drawable.resolveDensity(res, mVectorState.mVPathRenderer.mSourceDensity);
+        final int density = Drawable.resolveDensity(res, mVectorState.mVPathRenderer.mDensity);
+        if (mTargetDensity != density) {
+            mTargetDensity = density;
+            mDpiScaledDirty = true;
+        }
+
         mTintFilter = updateTintFilter(mTintFilter, mVectorState.mTint, mVectorState.mTintMode);
-        computeVectorSize();
     }
 
     @Override
@@ -422,17 +429,26 @@
 
     @Override
     public int getIntrinsicWidth() {
+        if (mDpiScaledDirty) {
+            computeVectorSize();
+        }
         return mDpiScaledWidth;
     }
 
     @Override
     public int getIntrinsicHeight() {
+        if (mDpiScaledDirty) {
+            computeVectorSize();
+        }
         return mDpiScaledHeight;
     }
 
     /** @hide */
     @Override
     public Insets getOpticalInsets() {
+        if (mDpiScaledDirty) {
+            computeVectorSize();
+        }
         return mDpiScaledInsets;
     }
 
@@ -444,7 +460,7 @@
         final VPathRenderer pathRenderer = mVectorState.mVPathRenderer;
         final Insets opticalInsets = pathRenderer.mOpticalInsets;
 
-        final int sourceDensity = pathRenderer.mSourceDensity;
+        final int sourceDensity = pathRenderer.mDensity;
         final int targetDensity = mTargetDensity;
         if (targetDensity != sourceDensity) {
             mDpiScaledWidth = Drawable.scaleFromDensity(
@@ -465,6 +481,8 @@
             mDpiScaledHeight = (int) pathRenderer.mBaseHeight;
             mDpiScaledInsets = opticalInsets;
         }
+
+        mDpiScaledDirty = false;
     }
 
     @Override
@@ -481,6 +499,11 @@
             return;
         }
 
+        final VPathRenderer path = state.mVPathRenderer;
+        final boolean changedDensity = path.setDensity(
+                Drawable.resolveDensity(t.getResources(), 0));
+        mDpiScaledDirty |= changedDensity;
+
         if (state.mThemeAttrs != null) {
             final TypedArray a = t.resolveAttributes(
                     state.mThemeAttrs, R.styleable.VectorDrawable);
@@ -492,6 +515,9 @@
             } finally {
                 a.recycle();
             }
+
+            // May have changed size.
+            mDpiScaledDirty = true;
         }
 
         // Apply theme to contained color state list.
@@ -499,7 +525,6 @@
             state.mTint = state.mTint.obtainForTheme(t);
         }
 
-        final VPathRenderer path = state.mVPathRenderer;
         if (path != null && path.canApplyTheme()) {
             path.applyTheme(t);
         }
@@ -565,21 +590,24 @@
     }
 
     @Override
-    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         final VectorDrawableState state = mVectorState;
-        final VPathRenderer pathRenderer = new VPathRenderer();
-        state.mVPathRenderer = pathRenderer;
+        state.mVPathRenderer = new VPathRenderer();
+        state.mVPathRenderer.setDensity(Drawable.resolveDensity(r, 0));
 
-        final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
         updateStateFromTypedArray(a);
         a.recycle();
 
+        mDpiScaledDirty = true;
+
         state.mCacheDirty = true;
-        inflateInternal(res, parser, attrs, theme);
+        inflateChildElements(r, parser, attrs, theme);
 
         // Update local properties.
-        updateLocalState(res);
+        updateLocalState(r);
     }
 
     private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
@@ -592,13 +620,6 @@
         // Extract the theme attributes, if any.
         state.mThemeAttrs = a.extractThemeAttrs();
 
-        // The density may have changed since the last update (if any). Any
-        // dimension-type attributes will need their default values scaled.
-        final int targetDensity = Drawable.resolveDensity(a.getResources(), 0);
-        final int sourceDensity = pathRenderer.mSourceDensity;
-        final float densityScale = targetDensity / (float) sourceDensity;
-        pathRenderer.mSourceDensity = targetDensity;
-
         final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
         if (tintMode != -1) {
             state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
@@ -626,11 +647,9 @@
         }
 
         pathRenderer.mBaseWidth = a.getDimension(
-                R.styleable.VectorDrawable_width,
-                pathRenderer.mBaseWidth * densityScale);
+                R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
         pathRenderer.mBaseHeight = a.getDimension(
-                R.styleable.VectorDrawable_height,
-                pathRenderer.mBaseHeight * densityScale);
+                R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
 
         if (pathRenderer.mBaseWidth <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
@@ -641,21 +660,17 @@
         }
 
         final int insetLeft = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetLeft,
-                (int) (pathRenderer.mOpticalInsets.left * densityScale));
+                R.styleable.VectorDrawable_opticalInsetLeft, pathRenderer.mOpticalInsets.left);
         final int insetTop = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetTop,
-                (int) (pathRenderer.mOpticalInsets.top * densityScale));
+                R.styleable.VectorDrawable_opticalInsetTop, pathRenderer.mOpticalInsets.top);
         final int insetRight = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetRight,
-                (int) (pathRenderer.mOpticalInsets.right * densityScale));
+                R.styleable.VectorDrawable_opticalInsetRight, pathRenderer.mOpticalInsets.right);
         final int insetBottom = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetBottom,
-                (int) (pathRenderer.mOpticalInsets.bottom * densityScale));
+                R.styleable.VectorDrawable_opticalInsetBottom, pathRenderer.mOpticalInsets.bottom);
         pathRenderer.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
 
-        final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
-                pathRenderer.getAlpha());
+        final float alphaInFloat = a.getFloat(
+                R.styleable.VectorDrawable_alpha, pathRenderer.getAlpha());
         pathRenderer.setAlpha(alphaInFloat);
 
         final String name = a.getString(R.styleable.VectorDrawable_name);
@@ -665,7 +680,7 @@
         }
     }
 
-    private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
+    private void inflateChildElements(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         final VectorDrawableState state = mVectorState;
         final VPathRenderer pathRenderer = state.mVPathRenderer;
@@ -929,7 +944,7 @@
         int mRootAlpha = 0xFF;
         String mRootName = null;
 
-        int mSourceDensity = DisplayMetrics.DENSITY_DEFAULT;
+        int mDensity = DisplayMetrics.DENSITY_DEFAULT;
 
         final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
 
@@ -966,12 +981,37 @@
             mChangingConfigurations = copy.mChangingConfigurations;
             mRootAlpha = copy.mRootAlpha;
             mRootName = copy.mRootName;
-            mSourceDensity = copy.mSourceDensity;
+            mDensity = copy.mDensity;
             if (copy.mRootName != null) {
                 mVGTargetsMap.put(copy.mRootName, this);
             }
         }
 
+        public final boolean setDensity(int targetDensity) {
+            if (mDensity != targetDensity) {
+                final int sourceDensity = mDensity;
+                mDensity = targetDensity;
+                applyDensityScaling(sourceDensity, targetDensity);
+                return true;
+            }
+            return false;
+        }
+
+        private void applyDensityScaling(int sourceDensity, int targetDensity) {
+            mBaseWidth = Drawable.scaleFromDensity(mBaseWidth, sourceDensity, targetDensity);
+            mBaseHeight = Drawable.scaleFromDensity(mBaseHeight, sourceDensity, targetDensity);
+
+            final int insetLeft = Drawable.scaleFromDensity(
+                    mOpticalInsets.left, sourceDensity, targetDensity, false);
+            final int insetTop = Drawable.scaleFromDensity(
+                    mOpticalInsets.top, sourceDensity, targetDensity, false);
+            final int insetRight = Drawable.scaleFromDensity(
+                    mOpticalInsets.right, sourceDensity, targetDensity, false);
+            final int insetBottom = Drawable.scaleFromDensity(
+                    mOpticalInsets.bottom, sourceDensity, targetDensity, false);
+            mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
+        }
+
         public boolean canApplyTheme() {
             return mRootGroup.canApplyTheme();
         }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index f0f8161..7c0676f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -31,6 +31,7 @@
 import android.provider.DocumentsProvider;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.FileNotFoundException;
@@ -59,6 +60,7 @@
 
     private MtpManager mMtpManager;
     private ContentResolver mResolver;
+    @GuardedBy("mDeviceToolkits")
     private Map<Integer, DeviceToolkit> mDeviceToolkits;
     private RootScanner mRootScanner;
     private Resources mResources;
@@ -222,9 +224,11 @@
 
     @Override
     public void onTrimMemory(int level) {
-      for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
-          toolkit.mDocumentLoader.clearCompletedTasks();
-      }
+        synchronized (mDeviceToolkits) {
+            for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
+                toolkit.mDocumentLoader.clearCompletedTasks();
+            }
+        }
     }
 
     @Override
@@ -254,21 +258,28 @@
     }
 
     void openDevice(int deviceId) throws IOException {
-        mMtpManager.openDevice(deviceId);
-        mDeviceToolkits.put(deviceId, new DeviceToolkit(mMtpManager, mResolver, mDatabase));
-        mRootScanner.scanNow();
+        synchronized (mDeviceToolkits) {
+            mMtpManager.openDevice(deviceId);
+            mDeviceToolkits.put(deviceId, new DeviceToolkit(mMtpManager, mResolver, mDatabase));
+        }
+        mRootScanner.resume();
     }
 
-    void closeDevice(int deviceId) throws IOException {
+    void closeDevice(int deviceId) throws IOException, InterruptedException {
         // TODO: Flush the device before closing (if not closed externally).
-        getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
-        mDeviceToolkits.remove(deviceId);
-        mDatabase.removeDeviceRows(deviceId);
-        mMtpManager.closeDevice(deviceId);
+        synchronized (mDeviceToolkits) {
+            getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
+            mDeviceToolkits.remove(deviceId);
+            mDatabase.removeDeviceRows(deviceId);
+            mMtpManager.closeDevice(deviceId);
+        }
         mRootScanner.notifyChange();
+        if (!hasOpenedDevices()) {
+            mRootScanner.pause();
+        }
     }
 
-    void close() throws InterruptedException {
+    synchronized void closeAllDevices() throws InterruptedException {
         boolean closed = false;
         for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
             try {
@@ -282,15 +293,30 @@
         }
         if (closed) {
             mRootScanner.notifyChange();
+            mRootScanner.pause();
         }
-        mRootScanner.close();
-        mDatabase.close();
     }
 
     boolean hasOpenedDevices() {
         return mMtpManager.getOpenedDeviceIds().length != 0;
     }
 
+    /**
+     * Finalize the content provider for unit tests.
+     */
+    @Override
+    public void shutdown() {
+        try {
+            closeAllDevices();
+        } catch (InterruptedException e) {
+            // It should fail unit tests by throwing runtime exception.
+            throw new RuntimeException(e.getMessage());
+        } finally {
+            mDatabase.close();
+            super.shutdown();
+        }
+    }
+
     private void notifyChildDocumentsChange(String parentDocumentId) {
         mResolver.notifyChange(
                 DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId),
@@ -299,11 +325,13 @@
     }
 
     private DeviceToolkit getDeviceToolkit(int deviceId) throws FileNotFoundException {
-        final DeviceToolkit toolkit = mDeviceToolkits.get(deviceId);
-        if (toolkit == null) {
-            throw new FileNotFoundException();
+        synchronized (mDeviceToolkits) {
+            final DeviceToolkit toolkit = mDeviceToolkits.get(deviceId);
+            if (toolkit == null) {
+                throw new FileNotFoundException();
+            }
+            return toolkit;
         }
-        return toolkit;
     }
 
     private PipeManager getPipeManager(Identifier identifier) throws FileNotFoundException {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
index 2d1af26..723dc14 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
@@ -67,10 +67,10 @@
                 provider.openDevice(device.getDeviceId());
                 return START_STICKY;
             } catch (IOException error) {
-                Log.d(MtpDocumentsProvider.TAG, error.getMessage());
+                Log.e(MtpDocumentsProvider.TAG, error.getMessage());
             }
         } else {
-            Log.d(MtpDocumentsProvider.TAG, "Received unknown intent action.");
+            Log.w(MtpDocumentsProvider.TAG, "Received unknown intent action.");
         }
         stopSelfIfNeeded();
         return Service.START_NOT_STICKY;
@@ -82,7 +82,7 @@
         unregisterReceiver(mReceiver);
         mReceiver = null;
         try {
-            provider.close();
+            provider.closeAllDevices();
         } catch (InterruptedException e) {
             Log.e(MtpDocumentsProvider.TAG, e.getMessage());
         }
@@ -105,8 +105,8 @@
                 final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
                 try {
                     provider.closeDevice(device.getDeviceId());
-                } catch (IOException error) {
-                    Log.d(MtpDocumentsProvider.TAG, error.getMessage());
+                } catch (IOException | InterruptedException error) {
+                    Log.e(MtpDocumentsProvider.TAG, error.getMessage());
                 }
                 stopSelfIfNeeded();
             }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index d9ed4ab..b0962dd 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -9,6 +9,10 @@
 import android.util.Log;
 
 import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
 
 final class RootScanner {
     /**
@@ -27,13 +31,18 @@
      */
     private final static long SHORT_POLLING_TIMES = 10;
 
+    /**
+     * Milliseconds we wait for background thread when pausing.
+     */
+    private final static long AWAIT_TERMINATION_TIMEOUT = 2000;
+
     final ContentResolver mResolver;
     final Resources mResources;
     final MtpManager mManager;
     final MtpDatabase mDatabase;
-    boolean mClosed = false;
-    int mPollingCount;
-    Thread mBackgroundThread;
+
+    ExecutorService mExecutor;
+    FutureTask<Void> mCurrentTask;
 
     RootScanner(
             ContentResolver resolver,
@@ -46,6 +55,9 @@
         mDatabase = database;
     }
 
+    /**
+     * Notifies a change of the roots list via ContentResolver.
+     */
     void notifyChange() {
         final Uri uri =
                 DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
@@ -56,74 +68,81 @@
      * Starts to check new changes right away.
      * If the background thread has already gone, it restarts another background thread.
      */
-    synchronized void scanNow() {
-        if (mClosed) {
+    synchronized void resume() {
+        if (mExecutor == null) {
+            // Only single thread updates the database.
+            mExecutor = Executors.newSingleThreadExecutor();
+        }
+        if (mCurrentTask != null) {
+            // Cancel previous task.
+            mCurrentTask.cancel(true);
+        }
+        mCurrentTask = new FutureTask<Void>(new UpdateRootsRunnable(), null);
+        mExecutor.submit(mCurrentTask);
+    }
+
+    /**
+     * Stops background thread and wait for its termination.
+     * @throws InterruptedException
+     */
+    synchronized void pause() throws InterruptedException {
+        if (mExecutor == null) {
             return;
         }
-        mPollingCount = 0;
-        if (mBackgroundThread == null) {
-            mBackgroundThread = new BackgroundLoaderThread();
-            mBackgroundThread.start();
-        } else {
-            notify();
+        mExecutor.shutdownNow();
+        if (!mExecutor.awaitTermination(AWAIT_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
+            Log.e(MtpDocumentsProvider.TAG, "Failed to terminate RootScanner's background thread.");
         }
+        mExecutor = null;
     }
 
-    void close() throws InterruptedException {
-        Thread thread;
-        synchronized (this) {
-            mClosed = true;
-            thread = mBackgroundThread;
-            if (mBackgroundThread == null) {
-                return;
-            }
-            notify();
-        }
-        thread.join();
-    }
-
-    private final class BackgroundLoaderThread extends Thread {
+    /**
+     * Runnable to scan roots and update the database information.
+     */
+    private final class UpdateRootsRunnable implements Runnable {
         @Override
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            synchronized (RootScanner.this) {
-                while (!mClosed) {
-                    final int[] deviceIds = mManager.getOpenedDeviceIds();
-                    if (deviceIds.length == 0) {
-                        break;
-                    }
-                    boolean changed = false;
-                    for (int deviceId : deviceIds) {
+            int pollingCount = 0;
+            while (!Thread.interrupted()) {
+                final int[] deviceIds = mManager.getOpenedDeviceIds();
+                if (deviceIds.length == 0) {
+                    return;
+                }
+                boolean changed = false;
+                for (int deviceId : deviceIds) {
+                    try {
+                        final MtpRoot[] roots = mManager.getRoots(deviceId);
                         mDatabase.startAddingRootDocuments(deviceId);
                         try {
-                            changed = mDatabase.putRootDocuments(
-                                    deviceId, mResources, mManager.getRoots(deviceId)) || changed;
-                        } catch (IOException|SQLiteException exp) {
-                            // The error may happen on the device. We would like to continue getting
-                            // roots for other devices.
-                            Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
-                            continue;
+                            if (mDatabase.putRootDocuments(deviceId, mResources, roots)) {
+                                changed = true;
+                            }
                         } finally {
-                            changed = mDatabase.stopAddingRootDocuments(deviceId) || changed;
+                            if (mDatabase.stopAddingRootDocuments(deviceId)) {
+                                changed = true;
+                            }
                         }
-                    }
-                    if (changed) {
-                        notifyChange();
-                    }
-                    mPollingCount++;
-                    try {
-                        // Use SHORT_POLLING_PERIOD for the first SHORT_POLLING_TIMES because it is
-                        // more likely to add new root just after the device is added.
-                        // TODO: Use short interval only for a device that is just added.
-                        RootScanner.this.wait(
-                                mPollingCount > SHORT_POLLING_TIMES ?
-                                        LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL);
-                    } catch (InterruptedException exception) {
-                        break;
+                    } catch (IOException | SQLiteException exception) {
+                        // The error may happen on the device. We would like to continue getting
+                        // roots for other devices.
+                        Log.e(MtpDocumentsProvider.TAG, exception.getMessage());
                     }
                 }
-
-                mBackgroundThread = null;
+                if (changed) {
+                    notifyChange();
+                }
+                pollingCount++;
+                try {
+                    // Use SHORT_POLLING_PERIOD for the first SHORT_POLLING_TIMES because it is
+                    // more likely to add new root just after the device is added.
+                    // TODO: Use short interval only for a device that is just added.
+                    Thread.sleep(pollingCount > SHORT_POLLING_TIMES ?
+                        LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL);
+                } catch (InterruptedException exp) {
+                    // The while condition handles the interrupted flag.
+                    continue;
+                }
             }
         }
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 82e08cd..cabb08d 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -49,11 +49,7 @@
 
     @Override
     public void tearDown() {
-        try {
-            mProvider.close();
-        } catch (InterruptedException e) {
-            fail();
-        }
+        mProvider.shutdown();
     }
 
     public void testOpenAndCloseDevice() throws Exception {
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index c7cf61a..5a6f1d1 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -61,7 +61,7 @@
 
         <activity
             android:name=".ui.PrintActivity"
-            android:configChanges="orientation|screenSize"
+            android:configChanges="screenSize|smallestScreenSize|orientation"
             android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
             android:theme="@style/PrintActivity">
             <intent-filter>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index fe67fd9..965e7a67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -239,7 +239,8 @@
             SystemServicesProxy ssp, Resources res) {
         Bitmap tdIcon = iconBitmap != null
                 ? iconBitmap
-                : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename);
+                : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename,
+                        taskKey.userId);
         if (tdIcon != null) {
             return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 4ecb80a..f3c66a5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -17,6 +17,8 @@
 package com.android.systemui.recents.views;
 
 import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -31,7 +33,6 @@
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.WindowManagerGlobal;
 import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.ExitRecentsWindowFirstAnimationFrameEvent;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsDebugFlags;
@@ -48,6 +49,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
@@ -93,7 +95,7 @@
             final boolean lockToTask, final Rect bounds, int destinationStack) {
         final ActivityOptions opts = ActivityOptions.makeBasic();
         if (bounds != null) {
-            opts.setBounds(bounds.isEmpty() ? null : bounds);
+            opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
         }
 
         final ActivityOptions.OnAnimationStartedListener animStartedListener;
@@ -244,8 +246,7 @@
         // Ensure we have a valid target stack id
         final int targetStackId = destinationStack != INVALID_STACK_ID ?
                 destinationStack : task.key.stackId;
-        if (targetStackId != FREEFORM_WORKSPACE_STACK_ID
-                && targetStackId != FULLSCREEN_WORKSPACE_STACK_ID) {
+        if (!StackId.useAnimationSpecForAppTransition(targetStackId)) {
             return null;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d3d9bef..f8ab35f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -2161,13 +2161,10 @@
         boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
         boolean isFullscreen = notification.fullScreenIntent != null;
         boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText);
-        boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
-                Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
         boolean accessibilityForcesLaunch = isFullscreen
                 && mAccessibilityManager.isTouchExplorationEnabled();
         boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent();
         boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
-                && isAllowed
                 && !accessibilityForcesLaunch
                 && !justLaunchedFullScreenIntent
                 && mPowerManager.isScreenOn()
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index ae9ddc0..40f7c5c 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1196,6 +1196,9 @@
             ClientState cs = mClients.remove(client.asBinder());
             if (cs != null) {
                 clearClientSessionLocked(cs);
+                if (mCurClient == cs) {
+                    mCurClient = null;
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 9ac4ba3..37d47c3 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -88,6 +88,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.text.SimpleDateFormat;
@@ -114,6 +115,7 @@
 public class AccountManagerService
         extends IAccountManager.Stub
         implements RegisteredServicesCacheListener<AuthenticatorDescription> {
+
     private static final String TAG = "AccountManagerService";
 
     private static final String DATABASE_NAME = "accounts.db";
@@ -2283,6 +2285,193 @@
         }
     }
 
+    @Override
+    public void startAddAccountSession(final IAccountManagerResponse response, final String accountType,
+            final String authTokenType, final String[] requiredFeatures,
+            final boolean expectActivityLaunch,
+            final Bundle optionsIn) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG,
+                    "startAddAccountSession: accountType " + accountType
+                    + ", response " + response
+                    + ", authTokenType " + authTokenType
+                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+                    + ", expectActivityLaunch " + expectActivityLaunch
+                    + ", caller's uid " + Binder.getCallingUid()
+                    + ", pid " + Binder.getCallingPid());
+        }
+        if (response == null) {
+            throw new IllegalArgumentException("response is null");
+        }
+        if (accountType == null) {
+            throw new IllegalArgumentException("accountType is null");
+        }
+
+        int userId = Binder.getCallingUserHandle().getIdentifier();
+        if (!canUserModifyAccounts(userId)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
+                        "User is not allowed to add an account!");
+            } catch (RemoteException re) {
+            }
+            showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
+            return;
+        }
+        if (!canUserModifyAccountsForType(userId, accountType)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+                        "User cannot modify accounts of this type (policy).");
+            } catch (RemoteException re) {
+            }
+            showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+                    userId);
+            return;
+        }
+
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
+        options.putInt(AccountManager.KEY_CALLER_UID, uid);
+        options.putInt(AccountManager.KEY_CALLER_PID, pid);
+
+        int usrId = UserHandle.getCallingUserId();
+        long identityToken = clearCallingIdentity();
+        try {
+            UserAccounts accounts = getUserAccounts(usrId);
+            logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
+                    TABLE_ACCOUNTS, uid);
+            new StartAccountSession(accounts, response, accountType, expectActivityLaunch,
+                    null /* accountName */, false /* authDetailsRequired */,
+                    true /* updateLastAuthenticationTime */) {
+                @Override
+                public void run() throws RemoteException {
+                    mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType,
+                            requiredFeatures, options);
+                }
+
+                @Override
+                protected String toDebugString(long now) {
+                    String requiredFeaturesStr = TextUtils.join(",", requiredFeatures);
+                    return super.toDebugString(now) + ", startAddAccountSession" + ", accountType "
+                            + accountType + ", requiredFeatures "
+                            + (requiredFeatures != null ? requiredFeaturesStr : null);
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */
+    private abstract class StartAccountSession extends Session {
+
+        public StartAccountSession(UserAccounts accounts, IAccountManagerResponse response,
+                String accountType, boolean expectActivityLaunch, String accountName,
+                boolean authDetailsRequired, boolean updateLastAuthenticationTime) {
+            super(accounts, response, accountType, expectActivityLaunch,
+                    true /* stripAuthTokenFromResult */, accountName, authDetailsRequired,
+                    updateLastAuthenticationTime);
+        }
+
+        @Override
+        public void onResult(Bundle result) {
+            mNumResults++;
+            Intent intent = null;
+
+            if (result != null
+                    && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+                /*
+                 * The Authenticator API allows third party authenticators to
+                 * supply arbitrary intents to other apps that they can run,
+                 * this can be very bad when those apps are in the system like
+                 * the System Settings.
+                 */
+                int authenticatorUid = Binder.getCallingUid();
+                long bid = Binder.clearCallingIdentity();
+                try {
+                    PackageManager pm = mContext.getPackageManager();
+                    ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
+                    int targetUid = resolveInfo.activityInfo.applicationInfo.uid;
+                    if (PackageManager.SIGNATURE_MATCH != pm.checkSignatures(authenticatorUid,
+                            targetUid)) {
+                        throw new SecurityException("Activity to be started with KEY_INTENT must "
+                                + "share Authenticator's signatures");
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(bid);
+                }
+            }
+
+            IAccountManagerResponse response;
+            if (mExpectActivityLaunch && result != null
+                    && result.containsKey(AccountManager.KEY_INTENT)) {
+                response = mResponse;
+            } else {
+                response = getResponseAndClose();
+            }
+            if (response == null) {
+                return;
+            }
+            if (result == null) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, getClass().getSimpleName() + " calling onError() on response "
+                            + response);
+                }
+                sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                        "null bundle returned");
+                return;
+            }
+
+            if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) {
+                // All AccountManager error codes are greater
+                // than 0
+                sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE),
+                        result.getString(AccountManager.KEY_ERROR_MESSAGE));
+                return;
+            }
+
+            // Strip auth token from result.
+            result.remove(AccountManager.KEY_AUTHTOKEN);
+
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG,
+                        getClass().getSimpleName() + " calling onResult() on response " + response);
+            }
+
+            // Get the session bundle created by authenticator. The
+            // bundle contains data necessary for finishing the session
+            // later. The session bundle will be encrypted here and
+            // decrypted later when trying to finish the session.
+            Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+            if (sessionBundle != null) {
+                String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
+                if (TextUtils.isEmpty(accountType)
+                        && !mAccountType.equalsIgnoreCase(mAccountType)) {
+                    Log.w(TAG, "Account type in session bundle doesn't match request.");
+                }
+                // Add accountType info to session bundle. This will
+                // override any value set by authenticator.
+                sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
+
+                // Encrypt session bundle before returning to caller.
+                try {
+                    CryptoHelper cryptoHelper = CryptoHelper.getInstance();
+                    Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
+                    result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle);
+                } catch (GeneralSecurityException e) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.v(TAG, "Failed to encrypt session bundle!", e);
+                    }
+                    sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                            "failed to encrypt session bundle");
+                    return;
+                }
+            }
+
+            sendResponse(response, result);
+        }
+    }
+
     private void showCantAddAccount(int errorCode, int userId) {
         Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
         cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
@@ -3336,6 +3525,11 @@
         private static String ACTION_CALLED_ACCOUNT_ADD = "action_called_account_add";
         private static String ACTION_CALLED_ACCOUNT_REMOVE = "action_called_account_remove";
 
+        // TODO: This action doesn't add account to accountdb. Account is only
+        // added in finishAddAccount or finishAddAccountAsUser which may be in
+        // a different user profile.
+        private static String ACTION_CALLED_START_ACCOUNT_ADD = "action_called_start_account_add";
+
         private static SimpleDateFormat dateFromat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
         private static void createDebugTable(SQLiteDatabase db) {
@@ -4300,4 +4494,29 @@
             return mContext;
         }
     }
+
+    private void sendResponse(IAccountManagerResponse response, Bundle result) {
+        try {
+            response.onResult(result);
+        } catch (RemoteException e) {
+            // if the caller is dead then there is no one to care about remote
+            // exceptions
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "failure while notifying response", e);
+            }
+        }
+    }
+
+    private void sendErrorResponse(IAccountManagerResponse response, int errorCode,
+            String errorMessage) {
+        try {
+            response.onError(errorCode, errorMessage);
+        } catch (RemoteException e) {
+            // if the caller is dead then there is no one to care about remote
+            // exceptions
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "failure while notifying response", e);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/accounts/CryptoHelper.java b/services/core/java/com/android/server/accounts/CryptoHelper.java
new file mode 100644
index 0000000..2b59b74
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/CryptoHelper.java
@@ -0,0 +1,140 @@
+package com.android.server.accounts;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * A crypto helper for encrypting and decrypting bundle with in-memory symmetric
+ * key for {@link AccountManagerService}.
+ */
+/* default */ class CryptoHelper {
+    private static final String TAG = "Account";
+
+    private static final String KEY_CIPHER = "cipher";
+    private static final String KEY_MAC = "mac";
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
+    private static final String MAC_ALGORITHM = "HMACSHA256";
+    private static final int IV_LENGTH = 16;
+
+    private static CryptoHelper sInstance;
+    // Keys used for encrypting and decrypting data returned in a Bundle.
+    private final SecretKeySpec mCipherKeySpec;
+    private final SecretKeySpec mMacKeySpec;
+    private final IvParameterSpec mIv;
+
+    /* default */ synchronized static CryptoHelper getInstance() throws NoSuchAlgorithmException {
+        if (sInstance == null) {
+            sInstance = new CryptoHelper();
+        }
+        return sInstance;
+    }
+
+    private CryptoHelper() throws NoSuchAlgorithmException {
+        KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
+        SecretKey skey = kgen.generateKey();
+        mCipherKeySpec = new SecretKeySpec(skey.getEncoded(), KEY_ALGORITHM);
+
+        kgen = KeyGenerator.getInstance(MAC_ALGORITHM);
+        skey = kgen.generateKey();
+        mMacKeySpec = new SecretKeySpec(skey.getEncoded(), MAC_ALGORITHM);
+
+        // Create random iv
+        byte[] iv = new byte[IV_LENGTH];
+        SecureRandom secureRandom = new SecureRandom();
+        secureRandom.nextBytes(iv);
+        mIv = new IvParameterSpec(iv);
+    }
+
+    @NonNull
+    /* default */ Bundle encryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
+        Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle.");
+        Parcel parcel = Parcel.obtain();
+        bundle.writeToParcel(parcel, 0);
+        byte[] bytes = parcel.marshall();
+        parcel.recycle();
+
+        Bundle encryptedBundle = new Bundle();
+
+        byte[] cipher = encrypt(bytes);
+        byte[] mac = createMac(cipher);
+
+        encryptedBundle.putByteArray(KEY_CIPHER, cipher);
+        encryptedBundle.putByteArray(KEY_MAC, mac);
+
+        return encryptedBundle;
+    }
+
+    @Nullable
+    /* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
+        Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle.");
+        byte[] cipherArray = bundle.getByteArray(KEY_CIPHER);
+        byte[] macArray = bundle.getByteArray(KEY_MAC);
+
+        if (!verifyMac(cipherArray, macArray)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Escrow mac mismatched!");
+            }
+            return null;
+        }
+
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.DECRYPT_MODE, mCipherKeySpec, mIv);
+        byte[] decryptedBytes = cipher.doFinal(cipherArray);
+
+        Parcel decryptedParcel = Parcel.obtain();
+        decryptedParcel.unmarshall(decryptedBytes, 0, decryptedBytes.length);
+        decryptedParcel.setDataPosition(0);
+        Bundle decryptedBundle = new Bundle();
+        decryptedBundle.readFromParcel(decryptedParcel);
+        decryptedParcel.recycle();
+        return decryptedBundle;
+    }
+
+    private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] macArray)
+            throws GeneralSecurityException {
+
+        if (cipherArray == null || cipherArray.length == 0 || macArray == null
+                || macArray.length == 0) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Cipher or MAC is empty!");
+            }
+            return false;
+        }
+        Mac mac = Mac.getInstance(MAC_ALGORITHM);
+        mac.init(mMacKeySpec);
+        mac.update(cipherArray);
+        return Arrays.equals(macArray, mac.doFinal());
+    }
+
+    @NonNull
+    private byte[] encrypt(@NonNull byte[] data) throws GeneralSecurityException {
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, mCipherKeySpec, mIv);
+        return cipher.doFinal(data);
+    }
+
+    @NonNull
+    private byte[] createMac(@NonNull byte[] cipher) throws GeneralSecurityException {
+        Mac mac = Mac.getInstance(MAC_ALGORITHM);
+        mac.init(mMacKeySpec);
+        return mac.doFinal(cipher);
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4b37205..3a0d80b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,72 +16,8 @@
 
 package com.android.server.am;
 
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static com.android.internal.util.XmlUtils.readBooleanAttribute;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
-import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
-import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS;
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
-
-import android.Manifest;
-import android.app.ActivityManager.StackId;
-import android.app.AppOpsManager;
-import android.app.ApplicationThreadNative;
-import android.app.BroadcastOptions;
-import android.app.IActivityContainer;
-import android.app.IActivityContainerCallback;
-import android.app.IAppTask;
-import android.app.ITaskStackListener;
-import android.app.ProfilerInfo;
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
-import android.appwidget.AppWidgetManager;
-import android.content.pm.PermissionInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.BatteryStats;
-import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.os.ResultReceiver;
-import android.os.Trace;
-import android.os.TransactionTooLargeException;
-import android.os.WorkSource;
-import android.os.storage.IMountService;
-import android.os.storage.MountServiceInternal;
-import android.os.storage.StorageManager;
-import android.provider.Settings.Global;
-import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.VoiceInteractionSession;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.view.Display;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -118,19 +54,16 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.WindowManagerService;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.Manifest;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManager.TaskThumbnailInfo;
 import android.app.ActivityManagerInternal;
@@ -140,24 +73,37 @@
 import android.app.ActivityThread;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.ApplicationErrorReport;
+import android.app.ApplicationThreadNative;
+import android.app.BroadcastOptions;
 import android.app.Dialog;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
 import android.app.IActivityController;
+import android.app.IAppTask;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
 import android.app.INotificationManager;
 import android.app.IProcessObserver;
 import android.app.IServiceConnection;
 import android.app.IStopUserCallback;
-import android.app.IUidObserver;
+import android.app.ITaskStackListener;
 import android.app.IUiAutomationConnection;
+import android.app.IUidObserver;
 import android.app.IUserSwitchObserver;
 import android.app.Instrumentation;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.backup.IBackupManager;
+import android.app.ProfilerInfo;
 import android.app.admin.DevicePolicyManager;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.app.backup.IBackupManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.appwidget.AppWidgetManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ClipData;
@@ -181,18 +127,24 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.UserInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.net.Proxy;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -210,21 +162,35 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.TransactionTooLargeException;
 import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.WorkSource;
+import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionSession;
 import android.text.format.DateUtils;
 import android.text.format.Time;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.DebugUtils;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
@@ -233,13 +199,12 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.Xml;
+import android.view.Display;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
 
-import dalvik.system.VMRuntime;
-
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.DataInputStream;
@@ -269,6 +234,100 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
+import static android.provider.Settings.Global.DEBUG_APP;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
+import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
 public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
@@ -1211,7 +1270,8 @@
     String mOrigDebugApp = null;
     boolean mOrigWaitForDebugger = false;
     boolean mAlwaysFinishActivities = false;
-    boolean mForceResizableActivites;
+    boolean mForceResizableActivities;
+    boolean mSupportsFreeformWindowManagement;
     IActivityController mController = null;
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
@@ -8827,12 +8887,19 @@
     }
 
     @Override
-    public Bitmap getTaskDescriptionIcon(String filename) {
-        if (!FileUtils.isValidExtFilename(filename)
-                || !filename.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
-            throw new IllegalArgumentException("Bad filename: " + filename);
+    public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
+        if (userId != UserHandle.getCallingUserId()) {
+            enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "getTaskDescriptionIcon");
         }
-        return mTaskPersister.getTaskDescriptionIcon(filename);
+        final File passedIconFile = new File(filePath);
+        final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
+                passedIconFile.getName());
+        if (!legitIconFile.getPath().equals(filePath)
+                || !filePath.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
+            throw new IllegalArgumentException("Bad file path: " + filePath);
+        }
+        return mTaskPersister.getTaskDescriptionIcon(filePath);
     }
 
     @Override
@@ -11805,21 +11872,21 @@
 
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
-        String debugApp = Settings.Global.getString(resolver, Settings.Global.DEBUG_APP);
-        boolean waitForDebugger = Settings.Global.getInt(
-            resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
-        boolean alwaysFinishActivities = Settings.Global.getInt(
-            resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
-        boolean forceRtl = Settings.Global.getInt(
-                resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
-        int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
-        boolean forceResizable = Settings.Global.getInt(
-                resolver, Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
-                defaultForceResizable) != 0;
-        // Transfer any global setting for forcing RTL layout, into a System Property
-        SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+        final boolean freeformWindowManagement =
+                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
 
-        Configuration configuration = new Configuration();
+        final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
+        final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
+        final boolean alwaysFinishActivities =
+                Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+        final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
+        final int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
+        final boolean forceResizable = Settings.Global.getInt(
+                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, defaultForceResizable) != 0;
+        // Transfer any global setting for forcing RTL layout, into a System Property
+        SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+
+        final Configuration configuration = new Configuration();
         Settings.System.getConfiguration(resolver, configuration);
         if (forceRtl) {
             // This will take care of setting the correct layout direction flags
@@ -11830,7 +11897,8 @@
             mDebugApp = mOrigDebugApp = debugApp;
             mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
             mAlwaysFinishActivities = alwaysFinishActivities;
-            mForceResizableActivites = forceResizable;
+            mForceResizableActivities = forceResizable;
+            mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
             // This happens before any activities are started, so we can
             // change mConfiguration in-place.
             updateConfigurationLocked(configuration, null, true);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index aa04bd7..ea8a12f 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -61,6 +61,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -1212,8 +1213,10 @@
         if (_taskDescription.getIconFilename() == null &&
                 (icon = _taskDescription.getIcon()) != null) {
             final String iconFilename = createImageFilename(createTime, task.taskId);
-            mStackSupervisor.mService.mTaskPersister.saveImage(icon, iconFilename);
-            _taskDescription.setIconFilename(iconFilename);
+            final File iconFile = new File(TaskPersister.getUserImagesDir(userId), iconFilename);
+            final String iconFilePath = iconFile.getAbsolutePath();
+            mStackSupervisor.mService.mTaskPersister.saveImage(icon, iconFilePath);
+            _taskDescription.setIconFilename(iconFilePath);
         }
         taskDescription = _taskDescription;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 35b7c78..124d2ef 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -99,7 +99,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
@@ -1924,9 +1923,9 @@
         boolean overrideBounds = false;
         Rect newBounds = null;
         if (options != null && (r.info.resizeable || (inTask != null && inTask.mResizeable))) {
-            if (options.hasBounds()) {
+            if (canUseActivityOptionsLaunchBounds(options)) {
                 overrideBounds = true;
-                newBounds = options.getBounds();
+                newBounds = options.getLaunchBounds();
             }
         }
 
@@ -2928,8 +2927,8 @@
         }
 
         if (task.mResizeable && options != null) {
-            if (options.hasBounds()) {
-                Rect bounds = options.getBounds();
+            if (canUseActivityOptionsLaunchBounds(options)) {
+                Rect bounds = options.getLaunchBounds();
                 task.updateOverrideConfiguration(bounds);
                 final int stackId = task.getLaunchStackId();
                 if (stackId != task.stack.mStackId) {
@@ -2953,6 +2952,12 @@
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
 
+    private boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
+        // We use the launch bounds in the activity options is the device supports freeform
+        // window management.
+        return options.hasLaunchBounds() && mService.mSupportsFreeformWindowManagement;
+    }
+
     ActivityStack getStack(int stackId) {
         return getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP);
     }
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 150baf0..9a00075 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -16,10 +16,11 @@
 
 package com.android.server.am;
 
-import android.content.pm.IPackageManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
+import android.os.Environment;
+import android.os.FileUtils;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -27,7 +28,6 @@
 import android.util.Xml;
 import android.os.Process;
 
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
@@ -44,6 +44,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 
 import libcore.io.IoUtils;
 
@@ -54,8 +55,10 @@
     /** When not flushing don't write out files faster than this */
     private static final long INTER_WRITE_DELAY_MS = 500;
 
-    /** When not flushing delay this long before writing the first file out. This gives the next
-     * task being launched a chance to load its resources without this occupying IO bandwidth. */
+    /**
+     * When not flushing delay this long before writing the first file out. This gives the next task
+     * being launched a chance to load its resources without this occupying IO bandwidth.
+     */
     private static final long PRE_TASK_DELAY_MS = 3000;
 
     /** The maximum number of entries to keep in the queue before draining it automatically. */
@@ -72,24 +75,23 @@
 
     private static final String TAG_TASK = "task";
 
-    static File sImagesDir;
-    static File sTasksDir;
-
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private final RecentTasks mRecentTasks;
 
-    /** Value determines write delay mode as follows:
-     *    < 0 We are Flushing. No delays between writes until the image queue is drained and all
-     * tasks needing persisting are written to disk. There is no delay between writes.
-     *    == 0 We are Idle. Next writes will be delayed by #PRE_TASK_DELAY_MS.
-     *    > 0 We are Actively writing. Next write will be at this time. Subsequent writes will be
-     * delayed by #INTER_WRITE_DELAY_MS. */
+    /**
+     * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
+     * until the image queue is drained and all tasks needing persisting are written to disk. There
+     * is no delay between writes. == 0 We are Idle. Next writes will be delayed by
+     * #PRE_TASK_DELAY_MS. > 0 We are Actively writing. Next write will be at this time. Subsequent
+     * writes will be delayed by #INTER_WRITE_DELAY_MS.
+     */
     private long mNextWriteTime = 0;
 
     private final LazyTaskWriterThread mLazyTaskWriterThread;
 
     private static class WriteQueueItem {}
+
     private static class TaskWriteQueueItem extends WriteQueueItem {
         final TaskRecord mTask;
 
@@ -97,12 +99,13 @@
             mTask = task;
         }
     }
+
     private static class ImageWriteQueueItem extends WriteQueueItem {
-        final String mFilename;
+        final String mFilePath;
         Bitmap mImage;
 
-        ImageWriteQueueItem(String filename, Bitmap image) {
-            mFilename = filename;
+        ImageWriteQueueItem(String filePath, Bitmap image) {
+            mFilePath = filePath;
             mImage = image;
         }
     }
@@ -111,19 +114,18 @@
 
     TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor,
             RecentTasks recentTasks) {
-        sTasksDir = new File(systemDir, TASKS_DIRNAME);
-        if (!sTasksDir.exists()) {
-            if (DEBUG) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
-            if (!sTasksDir.mkdir()) {
-                Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
+
+        final File legacyImagesDir = new File(systemDir, IMAGES_DIRNAME);
+        if (legacyImagesDir.exists()) {
+            if (!FileUtils.deleteContents(legacyImagesDir) || !legacyImagesDir.delete()) {
+                Slog.i(TAG, "Failure deleting legacy images directory: " + legacyImagesDir);
             }
         }
 
-        sImagesDir = new File(systemDir, IMAGES_DIRNAME);
-        if (!sImagesDir.exists()) {
-            if (DEBUG) Slog.d(TAG, "Creating images directory " + sTasksDir);
-            if (!sImagesDir.mkdir()) {
-                Slog.e(TAG, "Failure creating images directory " + sImagesDir);
+        final File legacyTasksDir = new File(systemDir, TASKS_DIRNAME);
+        if (legacyTasksDir.exists()) {
+            if (!FileUtils.deleteContents(legacyTasksDir) || !legacyTasksDir.delete()) {
+                Slog.i(TAG, "Failure deleting legacy tasks directory: " + legacyTasksDir);
             }
         }
 
@@ -144,8 +146,8 @@
         for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
             final WriteQueueItem item = mWriteQueue.get(queueNdx);
             if (item instanceof ImageWriteQueueItem &&
-                    ((ImageWriteQueueItem) item).mFilename.startsWith(taskString)) {
-                if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilename +
+                    ((ImageWriteQueueItem) item).mFilePath.startsWith(taskString)) {
+                if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilePath +
                         " from write queue");
                 mWriteQueue.remove(queueNdx);
             }
@@ -213,14 +215,14 @@
         }
     }
 
-    void saveImage(Bitmap image, String filename) {
+    void saveImage(Bitmap image, String filePath) {
         synchronized (this) {
             int queueNdx;
             for (queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
                 final WriteQueueItem item = mWriteQueue.get(queueNdx);
                 if (item instanceof ImageWriteQueueItem) {
                     ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
-                    if (imageWriteQueueItem.mFilename.equals(filename)) {
+                    if (imageWriteQueueItem.mFilePath.equals(filePath)) {
                         // replace the Bitmap with the new one.
                         imageWriteQueueItem.mImage = image;
                         break;
@@ -228,14 +230,14 @@
                 }
             }
             if (queueNdx < 0) {
-                mWriteQueue.add(new ImageWriteQueueItem(filename, image));
+                mWriteQueue.add(new ImageWriteQueueItem(filePath, image));
             }
             if (mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
                 mNextWriteTime = FLUSH_QUEUE;
             } else if (mNextWriteTime == 0) {
                 mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
             }
-            if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
+            if (DEBUG) Slog.d(TAG, "saveImage: filePath=" + filePath + " now=" +
                     SystemClock.uptimeMillis() + " mNextWriteTime=" +
                     mNextWriteTime + " Callers=" + Debug.getCallers(4));
             notifyAll();
@@ -244,22 +246,22 @@
         yieldIfQueueTooDeep();
     }
 
-    Bitmap getTaskDescriptionIcon(String filename) {
+    Bitmap getTaskDescriptionIcon(String filePath) {
         // See if it is in the write queue
-        final Bitmap icon = getImageFromWriteQueue(filename);
+        final Bitmap icon = getImageFromWriteQueue(filePath);
         if (icon != null) {
             return icon;
         }
-        return restoreImage(filename);
+        return restoreImage(filePath);
     }
 
-    Bitmap getImageFromWriteQueue(String filename) {
+    Bitmap getImageFromWriteQueue(String filePath) {
         synchronized (this) {
             for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
                 final WriteQueueItem item = mWriteQueue.get(queueNdx);
                 if (item instanceof ImageWriteQueueItem) {
                     ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
-                    if (imageWriteQueueItem.mFilename.equals(filename)) {
+                    if (imageWriteQueueItem.mFilePath.equals(filePath)) {
                         return imageWriteQueueItem.mImage;
                     }
                 }
@@ -275,7 +277,7 @@
         xmlSerializer.setOutput(stringWriter);
 
         if (DEBUG) xmlSerializer.setFeature(
-                    "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+                "http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
         // save task
         xmlSerializer.startDocument(null, true);
@@ -321,19 +323,22 @@
         return null;
     }
 
-    ArrayList<TaskRecord> restoreTasksLocked(final int [] validUserIds) {
-        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
+    private List<TaskRecord> restoreTasksForUserLocked(final int userId) {
+        final List<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
-        File[] recentFiles = sTasksDir.listFiles();
+        File userTasksDir = getUserTasksDir(userId);
+
+        File[] recentFiles = userTasksDir.listFiles();
         if (recentFiles == null) {
-            Slog.e(TAG, "Unable to list files from " + sTasksDir);
+            Slog.e(TAG, "restoreTasksForUser: Unable to list files from " + userTasksDir);
             return tasks;
         }
 
         for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
             File taskFile = recentFiles[taskNdx];
-            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
+            if (DEBUG) Slog.d(TAG, "restoreTasksForUser: userId=" + userId
+                    + ", taskFile=" + taskFile.getName());
             BufferedReader reader = null;
             boolean deleteFile = false;
             try {
@@ -348,30 +353,29 @@
                     if (event == XmlPullParser.START_TAG) {
                         if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
                         if (TAG_TASK.equals(name)) {
-                            final TaskRecord task =
-                                    TaskRecord.restoreFromXml(in, mStackSupervisor);
-                            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" +
-                                    task);
+                            final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);
+                            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task="
+                                    + task);
                             if (task != null) {
                                 // XXX Don't add to write queue... there is no reason to write
                                 // out the stuff we just read, if we don't write it we will
                                 // read the same thing again.
-                                //mWriteQueue.add(new TaskWriteQueueItem(task));
+                                // mWriteQueue.add(new TaskWriteQueueItem(task));
                                 final int taskId = task.taskId;
                                 mStackSupervisor.setNextTaskId(taskId);
                                 // Check if it's a valid user id. Don't add tasks for removed users.
-                                if (ArrayUtils.contains(validUserIds, task.userId)) {
+                                if (userId == task.userId) {
                                     task.isPersistable = true;
                                     tasks.add(task);
                                     recoveredTaskIds.add(taskId);
                                 }
                             } else {
-                                Slog.e(TAG, "Unable to restore taskFile=" + taskFile + ": " +
-                                        fileToString(taskFile));
+                                Slog.e(TAG, "restoreTasksForUser: Unable to restore taskFile="
+                                        + taskFile + ": " + fileToString(taskFile));
                             }
                         } else {
-                            Slog.wtf(TAG, "restoreTasksLocked Unknown xml event=" + event +
-                                    " name=" + name);
+                            Slog.wtf(TAG, "restoreTasksForUser: Unknown xml event=" + event
+                                    + " name=" + name);
                         }
                     }
                     XmlUtils.skipCurrentTag(in);
@@ -390,10 +394,19 @@
         }
 
         if (!DEBUG) {
-            removeObsoleteFiles(recoveredTaskIds);
+            removeObsoleteFiles(recoveredTaskIds, userTasksDir.listFiles());
+        }
+        return tasks;
+    }
+
+    ArrayList<TaskRecord> restoreTasksLocked(final int[] validUserIds) {
+        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
+
+        for (int userId : validUserIds) {
+            tasks.addAll(restoreTasksForUserLocked(userId));
         }
 
-        // Fixup task affiliation from taskIds
+        // Fix up task affiliation from taskIds
         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = tasks.get(taskNdx);
             task.setPrevAffiliate(taskIdToTask(task.mPrevAffiliateTaskId, tasks));
@@ -420,7 +433,7 @@
     }
 
     private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
-        if (DEBUG) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds=" + persistentTaskIds +
+        if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: persistentTaskIds=" + persistentTaskIds +
                 " files=" + files);
         if (files == null) {
             Slog.e(TAG, "File error accessing recents directory (too many files open?).");
@@ -434,14 +447,14 @@
                 final int taskId;
                 try {
                     taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
-                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: Found taskId=" + taskId);
                 } catch (Exception e) {
-                    Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
+                    Slog.wtf(TAG, "removeObsoleteFiles: Can't parse file=" + file.getName());
                     file.delete();
                     continue;
                 }
                 if (!persistentTaskIds.contains(taskId)) {
-                    if (DEBUG) Slog.d(TAG, "removeObsoleteFile: deleting file=" + file.getName());
+                    if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: deleting file=" + file.getName());
                     file.delete();
                 }
             }
@@ -449,13 +462,39 @@
     }
 
     private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
-        removeObsoleteFiles(persistentTaskIds, sTasksDir.listFiles());
-        removeObsoleteFiles(persistentTaskIds, sImagesDir.listFiles());
+        for (int userId : mService.getRunningUserIds()) {
+            removeObsoleteFiles(persistentTaskIds, getUserImagesDir(userId).listFiles());
+            removeObsoleteFiles(persistentTaskIds, getUserTasksDir(userId).listFiles());
+        }
     }
 
     static Bitmap restoreImage(String filename) {
         if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename);
-        return BitmapFactory.decodeFile(sImagesDir + File.separator + filename);
+        return BitmapFactory.decodeFile(filename);
+    }
+
+    static File getUserTasksDir(int userId) {
+        File userTasksDir = new File(Environment.getUserSystemDirectory(userId), TASKS_DIRNAME);
+
+        if (!userTasksDir.exists()) {
+            if (!userTasksDir.mkdir()) {
+                Slog.e(TAG, "Failure creating tasks directory for user " + userId + ": "
+                        + userTasksDir);
+            }
+        }
+        return userTasksDir;
+    }
+
+    static File getUserImagesDir(int userId) {
+        File userImagesDir = new File(Environment.getUserSystemDirectory(userId), IMAGES_DIRNAME);
+
+        if (!userImagesDir.exists()) {
+            if (!userImagesDir.mkdir()) {
+                Slog.e(TAG, "Failure creating images directory for user " + userId + ": "
+                        + userImagesDir);
+            }
+        }
+        return userImagesDir;
     }
 
     private class LazyTaskWriterThread extends Thread {
@@ -508,7 +547,6 @@
                                 INTER_WRITE_DELAY_MS + " msec. (" + mNextWriteTime + ")");
                     }
 
-
                     while (mWriteQueue.isEmpty()) {
                         if (mNextWriteTime != 0) {
                             mNextWriteTime = 0; // idle.
@@ -542,15 +580,15 @@
 
                 if (item instanceof ImageWriteQueueItem) {
                     ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
-                    final String filename = imageWriteQueueItem.mFilename;
+                    final String filePath = imageWriteQueueItem.mFilePath;
                     final Bitmap bitmap = imageWriteQueueItem.mImage;
-                    if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filename);
+                    if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filePath);
                     FileOutputStream imageFile = null;
                     try {
-                        imageFile = new FileOutputStream(new File(sImagesDir, filename));
+                        imageFile = new FileOutputStream(new File(filePath));
                         bitmap.compress(Bitmap.CompressFormat.PNG, 100, imageFile);
                     } catch (Exception e) {
-                        Slog.e(TAG, "saveImage: unable to save " + filename, e);
+                        Slog.e(TAG, "saveImage: unable to save " + filePath, e);
                     } finally {
                         IoUtils.closeQuietly(imageFile);
                     }
@@ -575,18 +613,21 @@
                         FileOutputStream file = null;
                         AtomicFile atomicFile = null;
                         try {
-                            atomicFile = new AtomicFile(new File(sTasksDir, String.valueOf(
-                                    task.taskId) + RECENTS_FILENAME + TASK_EXTENSION));
+                            atomicFile = new AtomicFile(new File(
+                                    getUserTasksDir(task.userId),
+                                    String.valueOf(task.taskId) + RECENTS_FILENAME
+                                    + TASK_EXTENSION));
                             file = atomicFile.startWrite();
                             file.write(stringWriter.toString().getBytes());
                             file.write('\n');
                             atomicFile.finishWrite(file);
+
                         } catch (IOException e) {
                             if (file != null) {
                                 atomicFile.failWrite(file);
                             }
-                            Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " +
-                                    e);
+                            Slog.e(TAG,
+                                    "Unable to open " + atomicFile + " for persisting. " + e);
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b214080..3fc6846 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -27,15 +27,23 @@
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
-import android.app.ActivityManager.TaskThumbnail;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskThumbnail;
 import android.app.ActivityManager.TaskThumbnailInfo;
@@ -58,8 +66,10 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.DisplayMetrics;
 import android.util.Slog;
+
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -237,7 +247,8 @@
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
-        mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
+        userId = UserHandle.getUserId(info.applicationInfo.uid);
+        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
         mLastThumbnailInfo = new TaskThumbnailInfo();
         taskId = _taskId;
         mAffiliatedTaskId = _taskId;
@@ -256,7 +267,8 @@
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
-        mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
+        userId = UserHandle.getUserId(info.applicationInfo.uid);
+        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
         mLastThumbnailInfo = thumbnailInfo;
         taskId = _taskId;
         mAffiliatedTaskId = _taskId;
@@ -276,7 +288,6 @@
 
         taskType = APPLICATION_ACTIVITY_TYPE;
         mTaskToReturnTo = HOME_ACTIVITY_TYPE;
-        userId = UserHandle.getUserId(info.applicationInfo.uid);
         lastTaskDescription = _taskDescription;
         mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
     }
@@ -294,7 +305,7 @@
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
-        mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
+        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename);
         mLastThumbnailInfo = lastThumbnailInfo;
         taskId = _taskId;
         intent = _intent;
@@ -326,7 +337,7 @@
         mNextAffiliateTaskId = nextTaskId;
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
-        mResizeable = resizeable || mService.mForceResizableActivites;
+        mResizeable = resizeable || mService.mForceResizableActivities;
         mPrivileged = privileged;
         ActivityInfo info = (mActivities.size() > 0) ? mActivities.get(0).info : null;
         mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
@@ -428,7 +439,7 @@
         } else {
             autoRemoveRecents = false;
         }
-        mResizeable = info.resizeable || mService.mForceResizableActivites;
+        mResizeable = info.resizeable || mService.mForceResizableActivities;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
@@ -537,7 +548,7 @@
                     mLastThumbnailFile.delete();
                 }
             } else {
-                mService.mTaskPersister.saveImage(thumbnail, mFilename);
+                mService.mTaskPersister.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
             }
             return true;
         }
@@ -549,7 +560,8 @@
         thumbs.thumbnailInfo = mLastThumbnailInfo;
         thumbs.thumbnailFileDescriptor = null;
         if (mLastThumbnail == null) {
-            thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(mFilename);
+            thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(
+                    mLastThumbnailFile.getAbsolutePath());
         }
         // Only load the thumbnail file if we don't have a thumbnail
         if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
@@ -682,7 +694,7 @@
         // Only set this based on the first activity
         if (mActivities.isEmpty()) {
             taskType = r.mActivityType;
-            if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivites) {
+            if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
                 mResizeable = r.info.resizeable;
             }
             isPersistable = r.isPersistable();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fd1e9dd..4424838 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1224,19 +1224,6 @@
         }
 
         @Override
-        public void setPackagePeekable(String pkg, int uid, boolean peekable) {
-            checkCallerIsSystem();
-
-            mRankingHelper.setPackagePeekable(pkg, uid, peekable);
-        }
-
-        @Override
-        public boolean getPackagePeekable(String pkg, int uid) {
-            checkCallerIsSystem();
-            return mRankingHelper.getPackagePeekable(pkg, uid);
-        }
-
-        @Override
         public void setPackageVisibilityOverride(String pkg, int uid, int visibility) {
             checkCallerIsSystem();
             mRankingHelper.setPackageVisibilityOverride(pkg, uid, visibility);
@@ -2157,14 +2144,6 @@
                             notification.priority = Notification.PRIORITY_HIGH;
                         }
                     }
-                    // force no heads up per package config
-                    if (!mRankingHelper.getPackagePeekable(pkg, callingUid)) {
-                        if (notification.extras == null) {
-                            notification.extras = new Bundle();
-                        }
-                        notification.extras.putInt(Notification.EXTRA_AS_HEADS_UP,
-                                Notification.HEADS_UP_NEVER);
-                    }
 
                     // 1. initial score: buckets of 10, around the app [-20..20]
                     final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 803db10..aea137b 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -20,10 +20,6 @@
 
     void setPackagePriority(String packageName, int uid, int priority);
 
-    boolean getPackagePeekable(String packageName, int uid);
-
-    void setPackagePeekable(String packageName, int uid, boolean peekable);
-
     int getPackageVisibilityOverride(String packageName, int uid);
 
     void setPackageVisibilityOverride(String packageName, int uid, int visibility);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 66381f5..f8b661f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -49,11 +49,9 @@
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
     private static final String ATT_PRIORITY = "priority";
-    private static final String ATT_PEEKABLE = "peekable";
     private static final String ATT_VISIBILITY = "visibility";
 
     private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
-    private static final boolean DEFAULT_PEEKABLE = true;
     private static final int DEFAULT_VISIBILITY =
             NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
 
@@ -141,7 +139,6 @@
                 if (TAG_PACKAGE.equals(tag)) {
                     int uid = safeInt(parser, ATT_UID, Record.UNKNOWN_UID);
                     int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
-                    boolean peekable = safeBool(parser, ATT_PEEKABLE, DEFAULT_PEEKABLE);
                     int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
                     String name = parser.getAttributeValue(null, ATT_NAME);
 
@@ -167,9 +164,6 @@
                         if (priority != DEFAULT_PRIORITY) {
                             r.priority = priority;
                         }
-                        if (peekable != DEFAULT_PEEKABLE) {
-                            r.peekable = peekable;
-                        }
                         if (vis != DEFAULT_VISIBILITY) {
                             r.visibility = vis;
                         }
@@ -200,8 +194,7 @@
         final int N = mRecords.size();
         for (int i = N - 1; i >= 0; i--) {
             final Record r = mRecords.valueAt(i);
-            if (r.priority == DEFAULT_PRIORITY && r.peekable == DEFAULT_PEEKABLE
-                    && r.visibility == DEFAULT_VISIBILITY) {
+            if (r.priority == DEFAULT_PRIORITY && r.visibility == DEFAULT_VISIBILITY) {
                 mRecords.remove(i);
             }
         }
@@ -223,9 +216,6 @@
             if (r.priority != DEFAULT_PRIORITY) {
                 out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
             }
-            if (r.peekable != DEFAULT_PEEKABLE) {
-                out.attribute(null, ATT_PEEKABLE, Boolean.toString(r.peekable));
-            }
             if (r.visibility != DEFAULT_VISIBILITY) {
                 out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
             }
@@ -348,22 +338,6 @@
     }
 
     @Override
-    public boolean getPackagePeekable(String packageName, int uid) {
-        final Record r = mRecords.get(recordKey(packageName, uid));
-        return r != null ? r.peekable : DEFAULT_PEEKABLE;
-    }
-
-    @Override
-    public void setPackagePeekable(String packageName, int uid, boolean peekable) {
-        if (peekable == getPackagePeekable(packageName, uid)) {
-            return;
-        }
-        getOrCreateRecord(packageName, uid).peekable = peekable;
-        removeDefaultRecords();
-        updateConfig();
-    }
-
-    @Override
     public int getPackageVisibilityOverride(String packageName, int uid) {
         final Record r = mRecords.get(recordKey(packageName, uid));
         return r != null ? r.visibility : DEFAULT_VISIBILITY;
@@ -415,10 +389,6 @@
                     pw.print(" priority=");
                     pw.print(Notification.priorityToString(r.priority));
                 }
-                if (r.peekable != DEFAULT_PEEKABLE) {
-                    pw.print(" peekable=");
-                    pw.print(r.peekable);
-                }
                 if (r.visibility != DEFAULT_VISIBILITY) {
                     pw.print(" visibility=");
                     pw.print(Notification.visibilityToString(r.visibility));
@@ -460,7 +430,6 @@
         String pkg;
         int uid = UNKNOWN_UID;
         int priority = DEFAULT_PRIORITY;
-        boolean peekable = DEFAULT_PEEKABLE;
         int visibility = DEFAULT_VISIBILITY;
     }
 
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 0420269..c9e1315 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -41,6 +41,9 @@
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+import android.os.SystemClock;
+import com.android.internal.logging.MetricsLogger;
+
 /**
  * This {@link NotificationSignalExtractor} attempts to validate
  * people references. Also elevates the priority of real people.
@@ -218,6 +221,7 @@
 
     private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras,
             float[] affinityOut) {
+        long start = SystemClock.elapsedRealtime();
         float affinity = NONE;
         if (extras == null) {
             return null;
@@ -251,6 +255,9 @@
         // record the best available data, so far:
         affinityOut[0] = affinity;
 
+        MetricsLogger.histogram(mBaseContext, "validate_people_cache_latency",
+                (int) (SystemClock.elapsedRealtime() - start));
+
         if (pendingLookups.isEmpty()) {
             if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity);
             return null;
@@ -430,6 +437,7 @@
 
         @Override
         public void work() {
+            long start = SystemClock.elapsedRealtime();
             if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey);
             long timeStartMs = System.currentTimeMillis();
             for (final String handle: mPendingLookups) {
@@ -468,6 +476,9 @@
                 mUsageStats.registerPeopleAffinity(mRecord, mContactAffinity > NONE,
                         mContactAffinity == STARRED_CONTACT, false /* cached */);
             }
+
+            MetricsLogger.histogram(mBaseContext, "validate_people_lookup_latency",
+                    (int) (SystemClock.elapsedRealtime() - start));
         }
 
         @Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 121ef21..ae6874f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5318,11 +5318,9 @@
     }
 
     private boolean shouldDispatchInputWhenNonInteractive() {
-        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()) {
+        // Send events to keyguard while the screen is on.
+        if (isKeyguardShowingAndNotOccluded() && mDisplay != null
+                && mDisplay.getState() != Display.STATE_OFF) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 943c9ed..8b1a830 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1480,7 +1480,9 @@
                                 mNextAppTransitionFutureCallback, null /* finishedCallback */,
                                 mNextAppTransitionScaleUp);
                         mNextAppTransitionFutureCallback = null;
-                        mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
+                        if (specs != null) {
+                            mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
+                        }
                     }
                     mService.requestTraversal();
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3ad2610..253fdad 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -55,6 +55,7 @@
 
 import android.Manifest;
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
@@ -3700,14 +3701,10 @@
         }
     }
 
-    void prolongAnimationsFromSpecs(AppTransitionAnimationSpec[] specs, boolean scaleUp) {
+    void prolongAnimationsFromSpecs(@NonNull AppTransitionAnimationSpec[] specs, boolean scaleUp) {
         // This is used by freeform <-> recents windows transition. We need to synchronize
         // the animation with the appearance of the content of recents, so we will make
         // animation stay on the first or last frame a little longer.
-        if (specs == null) {
-            Slog.wtf(TAG, "prolongAnimationsFromSpecs: AppTransitionAnimationSpec is null!");
-            return;
-        }
         mTmpTaskIds.clear();
         for (int i = specs.length - 1; i >= 0; i--) {
             mTmpTaskIds.put(specs[i].taskId, 0);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index e0f95cf..c734fab 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -772,7 +772,8 @@
         }
 
         private void updateUsbNotification() {
-            if (mNotificationManager == null || !mUseUsbNotification) return;
+            if (mNotificationManager == null || !mUseUsbNotification
+                    || ("0".equals(SystemProperties.get("persist.charging.notify")))) return;
             int id = 0;
             Resources r = mContext.getResources();
             if (mConnected || mHostConnected) {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
index ae4a57d..7ef7566 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -17,6 +17,7 @@
 package com.android.tools.layoutlib.create;
 
 import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
@@ -40,6 +41,7 @@
     private final String mClassName;
     private final Set<String> mDelegateMethods;
     private final Log mLog;
+    private boolean mIsStaticInnerClass;
 
     /**
      * Creates a new {@link DelegateClassAdapter} that can transform some methods
@@ -62,16 +64,30 @@
         mLog = log;
         mClassName = className;
         mDelegateMethods = delegateMethods;
+        // If this is an inner class, by default, we assume it's static. If it's not we will detect
+        // by looking at the fields (see visitField)
+        mIsStaticInnerClass = className.contains("$");
     }
 
     //----------------------------------
     // Methods from the ClassAdapter
 
     @Override
+    public FieldVisitor visitField(int access, String name, String desc, String signature,
+            Object value) {
+        if (mIsStaticInnerClass && "this$0".equals(name)) {
+            // Having a "this$0" field, proves that this class is not a static inner class.
+            mIsStaticInnerClass = false;
+        }
+
+        return super.visitField(access, name, desc, signature, value);
+    }
+
+    @Override
     public MethodVisitor visitMethod(int access, String name, String desc,
             String signature, String[] exceptions) {
 
-        boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+        boolean isStaticMethod = (access & Opcodes.ACC_STATIC) != 0;
         boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
 
         boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) ||
@@ -96,7 +112,8 @@
             MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions);
 
             DelegateMethodAdapter a = new DelegateMethodAdapter(
-                    mLog, null, mwDelegate, mClassName, name, desc, isStatic);
+                    mLog, null, mwDelegate, mClassName, name, desc, isStaticMethod,
+                    mIsStaticInnerClass);
 
             // A native has no code to visit, so we need to generate it directly.
             a.generateDelegateCode();
@@ -120,6 +137,7 @@
                                                      desc, signature, exceptions);
 
         return new DelegateMethodAdapter(
-                mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic);
+                mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStaticMethod,
+                mIsStaticInnerClass);
     }
 }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
index 12690db..cca9e57 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -85,6 +85,8 @@
     private String mDesc;
     /** True if the original method is static. */
     private final boolean mIsStatic;
+    /** True if the method is contained in a static inner class */
+    private final boolean mIsStaticInnerClass;
     /** The internal class name (e.g. <code>com/android/SomeClass$InnerClass</code>.) */
     private final String mClassName;
     /** The method name. */
@@ -120,7 +122,8 @@
             String className,
             String methodName,
             String desc,
-            boolean isStatic) {
+            boolean isStatic,
+            boolean isStaticClass) {
         super(Opcodes.ASM4);
         mLog = log;
         mOrgWriter = mvOriginal;
@@ -129,6 +132,7 @@
         mMethodName = methodName;
         mDesc = desc;
         mIsStatic = isStatic;
+        mIsStaticInnerClass = isStaticClass;
     }
 
     /**
@@ -206,7 +210,7 @@
         // by the 'this' of any outer class, if any.
         if (!mIsStatic) {
 
-            if (outerType != null) {
+            if (outerType != null && !mIsStaticInnerClass) {
                 // The first-level inner class has a package-protected member called 'this$0'
                 // that points to the outer class.
 
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
index 648cea43..e37a09b 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
@@ -27,6 +27,7 @@
 import com.android.tools.layoutlib.create.dataclass.ClassWithNative;
 import com.android.tools.layoutlib.create.dataclass.OuterClass;
 import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass;
+import com.android.tools.layoutlib.create.dataclass.OuterClass.StaticInnerClass;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -56,6 +57,8 @@
     private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
     private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
                                                    InnerClass.class.getSimpleName();
+    private static final String STATIC_INNER_CLASS_NAME =
+            OuterClass.class.getCanonicalName() + "$" + StaticInnerClass.class.getSimpleName();
 
     @Before
     public void setUp() throws Exception {
@@ -294,6 +297,61 @@
         }
     }
 
+    @Test
+    public void testDelegateStaticInner() throws Throwable {
+        // We'll delegate the "get" method of both the inner and outer class.
+        HashSet<String> delegateMethods = new HashSet<String>();
+        delegateMethods.add("get");
+
+        // Generate the delegate for the outer class.
+        ClassWriter cwOuter = new ClassWriter(0 /*flags*/);
+        String outerClassName = OUTER_CLASS_NAME.replace('.', '/');
+        DelegateClassAdapter cvOuter = new DelegateClassAdapter(
+                mLog, cwOuter, outerClassName, delegateMethods);
+        ClassReader cr = new ClassReader(OUTER_CLASS_NAME);
+        cr.accept(cvOuter, 0 /* flags */);
+
+        // Generate the delegate for the static inner class.
+        ClassWriter cwInner = new ClassWriter(0 /*flags*/);
+        String innerClassName = STATIC_INNER_CLASS_NAME.replace('.', '/');
+        DelegateClassAdapter cvInner = new DelegateClassAdapter(
+                mLog, cwInner, innerClassName, delegateMethods);
+        cr = new ClassReader(STATIC_INNER_CLASS_NAME);
+        cr.accept(cvInner, 0 /* flags */);
+
+        // Load the generated classes in a different class loader and try them
+        ClassLoader2 cl2 = null;
+        try {
+            cl2 = new ClassLoader2() {
+                @Override
+                public void testModifiedInstance() throws Exception {
+
+                    // Check the outer class
+                    Class<?> outerClazz2 = loadClass(OUTER_CLASS_NAME);
+                    Object o2 = outerClazz2.newInstance();
+                    assertNotNull(o2);
+
+                    // Check the inner class. Since it's not a static inner class, we need
+                    // to use the hidden constructor that takes the outer class as first parameter.
+                    Class<?> innerClazz2 = loadClass(STATIC_INNER_CLASS_NAME);
+                    Constructor<?> innerCons = innerClazz2.getConstructor();
+                    Object i2 = innerCons.newInstance();
+                    assertNotNull(i2);
+
+                    // The original StaticInner.get returns 100+10+20,
+                    // but the delegate makes it return 6+10+20
+                    assertEquals(6+10+20, callGet(i2, 10, 20));
+                    assertEquals(100+10+20, callGet_Original(i2, 10, 20));
+                }
+            };
+            cl2.add(OUTER_CLASS_NAME, cwOuter.toByteArray());
+            cl2.add(STATIC_INNER_CLASS_NAME, cwInner.toByteArray());
+            cl2.testModifiedInstance();
+        } catch (Throwable t) {
+            throw dumpGeneratedClass(t, cl2);
+        }
+    }
+
     //-------
 
     /**
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
index f083e76..6dfb816 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
@@ -45,6 +45,16 @@
         }
     }
 
+    public static class StaticInnerClass {
+        public StaticInnerClass() {
+        }
+
+        // StaticInnerClass.get returns 100 + a + b
+        public int get(int a, long b) {
+            return 100 + a + (int) b;
+        }
+    }
+
     @SuppressWarnings("unused")
     private String privateMethod() {
         return "outerPrivateMethod";
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java
new file mode 100644
index 0000000..a29439e
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java
@@ -0,0 +1,30 @@
+/*
+ * 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.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+import com.android.tools.layoutlib.create.dataclass.OuterClass.StaticInnerClass;
+
+/**
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class OuterClass_StaticInnerClass_Delegate {
+    // The delegate override of Inner.get return 6 + a + b
+    public static int get(StaticInnerClass inner, int a, long b) {
+        return 6 + a + (int) b;
+    }
+}