Merge "Fix SearchView measure for UNSPECIFIED height." into nyc-mr1-dev
diff --git a/Android.mk b/Android.mk
index 4ca3e22..2d52854 100644
--- a/Android.mk
+++ b/Android.mk
@@ -63,6 +63,7 @@
 	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
 	core/java/android/accounts/IAccountManager.aidl \
 	core/java/android/accounts/IAccountManagerResponse.aidl \
+	core/java/android/accounts/IAccountAccessTracker.aidl \
 	core/java/android/accounts/IAccountAuthenticator.aidl \
 	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
 	core/java/android/app/IActivityContainer.aidl \
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index f7f7c88..383cd01 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.AndroidException;
 import android.util.DisplayMetrics;
 import android.view.Display;
@@ -201,9 +202,11 @@
         try {
             if (density > 0) {
                 // TODO(multidisplay): For now Configuration only applies to main screen.
-                mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
+                mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
+                        UserHandle.USER_CURRENT);
             } else {
-                mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+                mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
+                        UserHandle.USER_CURRENT);
             }
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 7b83a30..6c16e32 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -16,9 +16,17 @@
 
 package android.accounts;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Set;
 
 /**
  * Value type that represents an Account in the {@link AccountManager}. This object is
@@ -26,8 +34,14 @@
  * suitable for use as the key of a {@link java.util.Map}
  */
 public class Account implements Parcelable {
+    private static final String TAG = "Account";
+
+    @GuardedBy("sAccessedAccounts")
+    private static final Set<Account> sAccessedAccounts = new ArraySet<>();
+
     public final String name;
     public final String type;
+    private final @Nullable IAccountAccessTracker mAccessTracker;
 
     public boolean equals(Object o) {
         if (o == this) return true;
@@ -44,6 +58,20 @@
     }
 
     public Account(String name, String type) {
+        this(name, type, null);
+    }
+
+    /**
+     * @hide
+     */
+    public Account(@NonNull Account other, @Nullable IAccountAccessTracker accessTracker) {
+        this(other.name, other.type, accessTracker);
+    }
+
+    /**
+     * @hide
+     */
+    public Account(String name, String type, IAccountAccessTracker accessTracker) {
         if (TextUtils.isEmpty(name)) {
             throw new IllegalArgumentException("the name must not be empty: " + name);
         }
@@ -52,11 +80,29 @@
         }
         this.name = name;
         this.type = type;
+        this.mAccessTracker = accessTracker;
     }
 
     public Account(Parcel in) {
         this.name = in.readString();
         this.type = in.readString();
+        this.mAccessTracker = IAccountAccessTracker.Stub.asInterface(in.readStrongBinder());
+        if (mAccessTracker != null) {
+            synchronized (sAccessedAccounts) {
+                if (sAccessedAccounts.add(this)) {
+                    try {
+                        mAccessTracker.onAccountAccessed();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error noting account access", e);
+                    }
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public IAccountAccessTracker getAccessTracker() {
+        return mAccessTracker;
     }
 
     public int describeContents() {
@@ -66,6 +112,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(name);
         dest.writeString(type);
+        dest.writeStrongInterface(mAccessTracker);
     }
 
     public static final Creator<Account> CREATOR = new Creator<Account>() {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index ed08a70..632e4b9 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -18,7 +18,6 @@
 
 import static android.Manifest.permission.GET_ACCOUNTS;
 
-import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
@@ -180,6 +179,14 @@
     public static final String KEY_ACCOUNT_TYPE = "accountType";
 
     /**
+     * Bundle key used for the {@link IAccountAccessTracker} account access tracker
+     * used for noting the account was accessed when unmarshalled from a parcel.
+     *
+     * @hide
+     */
+    public static final String KEY_ACCOUNT_ACCESS_TRACKER = "accountAccessTracker";
+
+    /**
      * Bundle key used for the auth token value in results
      * from {@link #getAuthToken} and friends.
      */
@@ -268,13 +275,13 @@
     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
 
     /**
-     * Token for the special case where a UID has access only to an account
-     * but no authenticator specific auth tokens.
+     * Token type for the special case where a UID has access only to an account
+     * but no authenticator specific auth token types.
      *
      * @hide
      */
-    public static final String ACCOUNT_ACCESS_TOKEN =
-            "com.android.abbfd278-af8b-415d-af8b-7571d5dab133";
+    public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
+            "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
 
     private final Context mContext;
     private final IAccountManager mService;
@@ -814,7 +821,9 @@
             public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
                 String name = bundle.getString(KEY_ACCOUNT_NAME);
                 String type = bundle.getString(KEY_ACCOUNT_TYPE);
-                return new Account(name, type);
+                IAccountAccessTracker tracker = IAccountAccessTracker.Stub.asInterface(
+                        bundle.getBinder(KEY_ACCOUNT_ACCESS_TRACKER));
+                return new Account(name, type, tracker);
             }
         }.start();
     }
@@ -2270,6 +2279,7 @@
                                     result.putString(KEY_ACCOUNT_NAME, null);
                                     result.putString(KEY_ACCOUNT_TYPE, null);
                                     result.putString(KEY_AUTHTOKEN, null);
+                                    result.putBinder(KEY_ACCOUNT_ACCESS_TRACKER, null);
                                     try {
                                         mResponse.onResult(result);
                                     } catch (RemoteException e) {
@@ -2295,9 +2305,13 @@
                                         public void onResult(Bundle value) throws RemoteException {
                                             Account account = new Account(
                                                     value.getString(KEY_ACCOUNT_NAME),
-                                                    value.getString(KEY_ACCOUNT_TYPE));
-                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
-                                                    mActivity, mMyCallback, mHandler);
+                                                    value.getString(KEY_ACCOUNT_TYPE),
+                                                    IAccountAccessTracker.Stub.asInterface(
+                                                            value.getBinder(
+                                                                    KEY_ACCOUNT_ACCESS_TRACKER)));
+                                            mFuture = getAuthToken(account, mAuthTokenType,
+                                                    mLoginOptions,  mActivity, mMyCallback,
+                                                    mHandler);
                                         }
 
                                         @Override
@@ -2344,7 +2358,9 @@
                         setException(new AuthenticatorException("account not in result"));
                         return;
                     }
-                    final Account account = new Account(accountName, accountType);
+                    final IAccountAccessTracker tracker = IAccountAccessTracker.Stub.asInterface(
+                            result.getBinder(KEY_ACCOUNT_ACCESS_TRACKER));
+                    final Account account = new Account(accountName, accountType, tracker);
                     mNumAccounts = 1;
                     getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
                             mMyCallback, mHandler);
diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
index d777643..68c17c3 100644
--- a/core/java/android/accounts/AccountManagerInternal.java
+++ b/core/java/android/accounts/AccountManagerInternal.java
@@ -28,6 +28,21 @@
 public abstract class AccountManagerInternal {
 
     /**
+     * Listener for explicit UID account access grant changes.
+     */
+    public interface OnAppPermissionChangeListener {
+
+        /**
+         * Called when the explicit grant state for a given UID to
+         * access an account changes.
+         *
+         * @param account The account
+         * @param uid The UID for which the grant changed
+         */
+        public void onAppPermissionChanged(Account account, int uid);
+    }
+
+    /**
      * Requests that a given package is given access to an account.
      * The provided callback will be invoked with a {@link android.os.Bundle}
      * containing the result which will be a boolean value mapped to the
@@ -38,7 +53,38 @@
      * @param userId Concrete user id for which to request.
      * @param callback A callback for receiving the result.
      */
-    public abstract void requestAccountAccess(@NonNull  Account account,
+    public abstract void requestAccountAccess(@NonNull Account account,
             @NonNull String packageName, @IntRange(from = 0) int userId,
             @NonNull RemoteCallback callback);
+
+    /**
+     * Check whether the given UID has access to the account.
+     *
+     * @param account The account
+     * @param uid The UID
+     * @return Whether the UID can access the account
+     */
+    public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid);
+
+    /**
+     * Adds a listener for explicit UID account access grant changes.
+     *
+     * @param listener The listener
+     */
+    public abstract void addOnAppPermissionChangeListener(
+            @NonNull OnAppPermissionChangeListener listener);
+
+    /**
+     * Backups the account access permissions.
+     * @param userId The user for which to backup.
+     * @return The backup data.
+     */
+    public abstract byte[] backupAccountAccessPermissions(int userId);
+
+    /**
+     * Restores the account access permissions.
+     * @param data The restore data.
+     * @param userId The user for which to restore.
+     */
+    public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
 }
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 8d0ce58..38eab29 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -108,7 +108,7 @@
             }
         };
 
-        if (!AccountManager.ACCOUNT_ACCESS_TOKEN.equals(mAuthTokenType)) {
+        if (!AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(mAuthTokenType)) {
             AccountManager.get(this).getAuthTokenLabel(mAccount.type,
                     mAuthTokenType, callback, null);
         }
diff --git a/core/java/android/accounts/IAccountAccessTracker.aidl b/core/java/android/accounts/IAccountAccessTracker.aidl
new file mode 100644
index 0000000..e12b3d1
--- /dev/null
+++ b/core/java/android/accounts/IAccountAccessTracker.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+/**
+ * Interface to track which apps accessed an account
+ *
+ * @hide
+ */
+oneway interface IAccountAccessTracker {
+    void onAccountAccessed();
+}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 8afca78..5dead28 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -194,7 +194,7 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about using fragments, read the
- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
  * </div>
  *
  * <a name="OlderPlatforms"></a>
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index cd7665c..bfaf332 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -59,7 +59,7 @@
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about using fragments, read the
- * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
  * </div>
  *
  * While the FragmentManager API was introduced in
diff --git a/core/java/android/app/package.html b/core/java/android/app/package.html
index f37f1dc..b259cad 100644
--- a/core/java/android/app/package.html
+++ b/core/java/android/app/package.html
@@ -34,7 +34,7 @@
 <p>For information about using some the classes in this package, see the following
 documents: <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>, <a
 href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>, <a
-href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>, <a
+href="{@docRoot}guide/components/fragments.html">Fragments</a>, <a
 href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a>, <a
 href="{@docRoot}guide/topics/ui/dialogs.html">Creating Dialogs</a>, and <a
 href="{@docRoot}guide/topics/ui/notifiers/index.html">Notifying the User</a>.</p>
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index b3320d6..daa1b93 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1877,6 +1877,7 @@
         if (extras != null) {
             String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
             if (!TextUtils.isEmpty(accountName)) {
+                // TODO: No references to Google in AOSP
                 account = new Account(accountName, "com.google");
             }
             extras.remove(SYNC_EXTRAS_ACCOUNT);
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 22ab43b..d07b5457 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -265,6 +265,7 @@
     public static final String SCHEME_HTTPS = "https";
 
     private int mPriority;
+    private int mOrder;
     private final ArrayList<String> mActions;
     private ArrayList<String> mCategories = null;
     private ArrayList<String> mDataSchemes = null;
@@ -425,6 +426,7 @@
      */
     public IntentFilter(IntentFilter o) {
         mPriority = o.mPriority;
+        mOrder = o.mOrder;
         mActions = new ArrayList<String>(o.mActions);
         if (o.mCategories != null) {
             mCategories = new ArrayList<String>(o.mCategories);
@@ -477,6 +479,16 @@
         return mPriority;
     }
 
+    /** @hide */
+    public final void setOrder(int order) {
+        mOrder = order;
+    }
+
+    /** @hide */
+    public final int getOrder() {
+        return mOrder;
+    }
+
     /**
      * Set whether this filter will needs to be automatically verified against its data URIs or not.
      * The default is false.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 426e78d..79f1151 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6333,21 +6333,6 @@
         public static final String WEB_ACTION_ENABLED = "web_action_enabled";
 
         /**
-         * The uptime when tasks were last persisted.  This is used to adjust the previous task
-         * active times to be relative to the current boot time.
-         * @hide
-         */
-        public static final String TASK_PERSISTER_LAST_WRITE_UPTIME = "task_persister_write_uptime";
-
-        /**
-         * Used by Overview to keep track of the last visible task's active time to determine what
-         * should tasks be visible.
-         * @hide
-         */
-        public static final String OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME =
-                "overview_last_visible_task_active_uptime";
-
-        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
new file mode 100644
index 0000000..6531aef
--- /dev/null
+++ b/core/java/android/util/PackageUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Helper functions applicable to packages.
+ * @hide
+ */
+public final class PackageUtils {
+    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+    private PackageUtils() {
+        /* hide constructor */
+    }
+
+    /**
+     * Computes the SHA256 digest of the signing cert for a package.
+     * @param packageManager The package manager.
+     * @param packageName The package for which to generate the digest.
+     * @param userId The user for which to generate the digest.
+     * @return The digest or null if the package does not exist for this user.
+     */
+    public static @Nullable String computePackageCertSha256Digest(
+            @NonNull PackageManager packageManager,
+            @NonNull String packageName, int userId) {
+        final PackageInfo packageInfo;
+        try {
+            packageInfo = packageManager.getPackageInfoAsUser(packageName,
+                    PackageManager.GET_SIGNATURES, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+        return computeCertSha256Digest(packageInfo.signatures[0]);
+    }
+
+    /**
+     * Computes the SHA256 digest of a cert.
+     * @param signature The signature.
+     * @return The digest or null if an error occurs.
+     */
+    public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
+        return computeSha256Digest(signature.toByteArray());
+    }
+
+    /**
+     * Computes the SHA256 digest of some data.
+     * @param data The data.
+     * @return The digest or null if an error occurs.
+     */
+    public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance("SHA256");
+        } catch (NoSuchAlgorithmException e) {
+            /* can't happen */
+            return null;
+        }
+
+        messageDigest.update(data);
+
+        final byte[] digest = messageDigest.digest();
+        final int digestLength = digest.length;
+        final int charCount = 2 * digestLength;
+
+        final char[] chars = new char[charCount];
+        for (int i = 0; i < digestLength; i++) {
+            final int byteHex = digest[i] & 0xFF;
+            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
+            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
+        }
+        return new String(chars);
+    }
+}
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index b0f15b5..a394f35 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -377,6 +377,10 @@
      * The object is intended to provide local information about the drag and drop operation. For
      * example, it can indicate whether the drag and drop operation is a copy or a move.
      * <p>
+     * The local state is available only to views in the activity which has started the drag
+     * operation. In all other activities this method will return null
+     * </p>
+     * <p>
      *  This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
      * </p>
      * @return The local state object sent to the system by startDrag().
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 81469c8..83feb88 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -73,8 +73,8 @@
     void clearForcedDisplaySize(int displayId);
     int getInitialDisplayDensity(int displayId);
     int getBaseDisplayDensity(int displayId);
-    void setForcedDisplayDensity(int displayId, int density);
-    void clearForcedDisplayDensity(int displayId);
+    void setForcedDisplayDensityForUser(int displayId, int density, int userId);
+    void clearForcedDisplayDensityForUser(int displayId, int userId);
     void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
 
     void setOverscan(int displayId, int left, int top, int right, int bottom);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 908658f..a0afeba 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20655,8 +20655,10 @@
      * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
      * drag shadow.
      * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
-     * drop operation. This Object is put into every DragEvent object sent by the system during the
-     * current drag.
+     * drop operation. When dispatching drag events to views in the same activity this object
+     * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other
+     * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()}
+     * will return null).
      * <p>
      * myLocalState is a lightweight mechanism for the sending information from the dragged View
      * to the target Views. For example, it can contain flags that differentiate between a
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index eca10cb..a400d90 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -460,7 +460,7 @@
                 // the view isn't yet added, so let's try not to crash.
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
-                    mWM.removeView(mView);
+                    mWM.removeViewImmediate(mView);
                 }
 
                 mView = null;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0a4ac0d..1e26c92 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1469,7 +1469,7 @@
                 boolean found = false;
                 // Only loop to the end of into as it was before we started; no dupes in from.
                 for (int j = 0; j < intoCount; j++) {
-                    final ResolvedComponentInfo rci = into.get(i);
+                    final ResolvedComponentInfo rci = into.get(j);
                     if (isSameResolvedComponent(newInfo, rci)) {
                         found = true;
                         rci.add(intent, newInfo);
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index a4b5a8e..cb2b019 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -145,7 +145,11 @@
                 if (itemType == TYPE_HEADER_SUGGESTED) {
                     textView.setText(R.string.language_picker_section_suggested);
                 } else {
-                    textView.setText(R.string.language_picker_section_all);
+                    if (mCountryMode) {
+                        textView.setText(R.string.region_picker_section_all);
+                    } else {
+                        textView.setText(R.string.language_picker_section_all);
+                    }
                 }
                 textView.setTextLocale(Locale.getDefault());
                 break;
diff --git a/core/java/com/android/server/backup/AccountManagerBackupHelper.java b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
new file mode 100644
index 0000000..39b18c0
--- /dev/null
+++ b/core/java/com/android/server/backup/AccountManagerBackupHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.accounts.AccountManagerInternal;
+import android.app.backup.BlobBackupHelper;
+import android.os.UserHandle;
+import android.util.Slog;
+import com.android.server.LocalServices;
+
+/**
+ * Helper for handling backup of account manager specific state.
+ */
+public class AccountManagerBackupHelper extends BlobBackupHelper {
+    private static final String TAG = "AccountsBackup";
+    private static final boolean DEBUG = false;
+
+    // current schema of the backup state blob
+    private static final int STATE_VERSION = 1;
+
+    // key under which the account access grant state blob is committed to backup
+    private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants";
+
+    public AccountManagerBackupHelper() {
+        super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS);
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
+        if (DEBUG) {
+            Slog.d(TAG, "Handling backup of " + key);
+        }
+        try {
+            switch (key) {
+                case KEY_ACCOUNT_ACCESS_GRANTS: {
+                    return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM);
+                }
+
+                default: {
+                    Slog.w(TAG, "Unexpected backup key " + key);
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to store payload " + key);
+        }
+
+        return new byte[0];
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
+        if (DEBUG) {
+            Slog.d(TAG, "Handling restore of " + key);
+        }
+        try {
+            switch (key) {
+                case KEY_ACCOUNT_ACCESS_GRANTS: {
+                    am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM);
+                } break;
+
+                default: {
+                    Slog.w(TAG, "Unexpected restore key " + key);
+                }
+            }
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to restore key " + key);
+        }
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 9d296fa..5375651 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -49,6 +49,7 @@
     private static final String PERMISSION_HELPER = "permissions";
     private static final String USAGE_STATS_HELPER = "usage_stats";
     private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
+    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
 
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
@@ -82,6 +83,7 @@
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
+        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
         super.onBackup(oldState, data, newState);
     }
 
@@ -111,6 +113,7 @@
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
+        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
 
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9459257..b926270 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -350,9 +350,16 @@
     postData(msgType, dataPtr, NULL);
 }
 
-void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) {
-    // This is not needed at app layer. This should not be called because JNICameraContext cannot
-    // start video recording.
+void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t* handle) {
+    // Video buffers are not needed at app layer so just return the video buffers here.
+    // This may be called when stagefright just releases camera but there are still outstanding
+    // video buffers.
+    if (mCamera != nullptr) {
+        mCamera->releaseRecordingFrameHandle(handle);
+    } else {
+        native_handle_close(handle);
+        native_handle_delete(handle);
+    }
 }
 
 void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index a24aa31..8eb39e1 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -337,11 +337,15 @@
     return 0;
 }
 
-static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
+static void query_hub_for_apps(uint32_t hubHandle) {
     hub_message_t msg;
     query_apps_request_t queryMsg;
 
-    queryMsg.app_name.id = appId;
+    // TODO(b/30835598): When we're able to tell which request our
+    //     response matches, then we should allow this to be more
+    //     targetted, instead of always being every app in the
+    //     system.
+    queryMsg.app_name.id = ALL_APPS;
 
     msg.message_type = CONTEXT_HUB_QUERY_APPS;
     msg.message_len  = sizeof(queryMsg);
@@ -354,9 +358,9 @@
     }
 }
 
-static void sendQueryForApps(uint64_t appId) {
+static void sendQueryForApps() {
     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
-        query_hub_for_apps(appId, i);
+        query_hub_for_apps(i);
     }
 }
 
@@ -386,9 +390,6 @@
 
 static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
         jint appInstanceHandle, JNIEnv *env) {
-
-    ALOGI("Loading App");
-
     // Not checking if the apps are indeed distinct
     app_instance_info_s entry;
     assert(appInfo);
@@ -404,13 +405,14 @@
 
     db.appInstances[appInstanceHandle] = entry;
 
-    // Finally - let the service know of this app instance
+    // Finally - let the service know of this app instance, to populate
+    // the Java cache.
     env->CallIntMethod(db.jniInfo.jContextHubService,
                        db.jniInfo.contextHubServiceAddAppInstance,
                        hubHandle, entry.instanceId, entry.truncName,
                        entry.appInfo.version);
 
-    ALOGW("%s App 0x%" PRIx64 " on hub Handle %" PRId32
+    ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
           " as appInstance %" PRId32, action, entry.truncName,
           entry.hubHandle, appInstanceHandle);
 
@@ -532,7 +534,7 @@
             }
         }
 
-        sendQueryForApps(ALL_APPS);
+        sendQueryForApps();
     } else {
         ALOGW("No Context Hub Module present");
     }
@@ -576,16 +578,63 @@
             return -1;
     }
 
-    int numApps = msgLen/sizeof(hub_app_info);
-    hub_app_info info;
+    int numApps = msgLen / sizeof(hub_app_info);
     const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
 
-    for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
-        memcpy(&info, unalignedInfoAddr, sizeof(info));
+    // We use this information to sync our JNI and Java caches of nanoapp info.
+    // We want to accomplish two things here:
+    // 1) Remove entries from our caches which are stale, and pertained to
+    //    apps no longer running on Context Hub.
+    // 2) Populate our caches with the latest information of all these apps.
+
+    // We make a couple of assumptions here:
+    // A) The JNI and Java caches are in sync with each other (this isn't
+    //    necessarily true; any failure of a single call into Java land to
+    //    update its cache will leave that cache in a bad state.  For NYC,
+    //    we're willing to tolerate this for now).
+    // B) The total number of apps is relatively small, so horribly inefficent
+    //    algorithms aren't too painful.
+    // C) We're going to call this relatively infrequently, so its inefficency
+    //    isn't a big impact.
+
+
+    // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
+    // assumption (B).  Per assumption (A), it is sufficient to iterate
+    // over just the JNI cache.
+    auto end = db.appInstances.end();
+    for (auto current = db.appInstances.begin(); current != end; ) {
+        app_instance_info_s cache_entry = current->second;
+        // We perform our iteration here because if we call
+        // delete_app_instance() below, it will erase() this entry.
+        current++;
+        bool entryIsStale = true;
+        for (int i = 0; i < numApps; i++) {
+            // We use memcmp since this could be unaligned.
+            if (memcmp(&unalignedInfoAddr[i].app_name.id,
+                       &cache_entry.appInfo.app_name.id,
+                       sizeof(cache_entry.appInfo.app_name.id)) == 0) {
+                // We found a match; this entry is current.
+                entryIsStale = false;
+                break;
+            }
+        }
+        if (entryIsStale) {
+            delete_app_instance(cache_entry.instanceId, env);
+        }
+    }
+
+    // (2).  Update our caches with the latest.
+    for (int i = 0; i < numApps; i++) {
+        hub_app_info query_info;
+        memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
         // We will only have one instance of the app
         // TODO : Change this logic once we support multiple instances of the same app
-        jint appInstance = get_app_instance_for_app_id(info.app_name.id);
-        add_app_instance(&info, hubHandle, appInstance, env);
+        jint appInstance = get_app_instance_for_app_id(query_info.app_name.id);
+        if (appInstance == -1) {
+            // This is a previously unknown app, let's allocate an "id" for it.
+            appInstance = generate_id();
+        }
+        add_app_instance(&query_info, hubHandle, appInstance, env);
     }
 
     return 0;
@@ -709,7 +758,12 @@
             ALOGW("Could not attach to JVM !");
             success = false;
         }
-        sendQueryForApps(info->appInfo.app_name.id);
+        // While we just called add_app_instance above, our info->appInfo was
+        // incomplete (for example, the 'version' is hardcoded to -1).  So we
+        // trigger an additional query to the CHRE, so we'll be able to get
+        // all the app "info", and have our JNI and Java caches with the
+        // full information.
+        sendQueryForApps();
     } else {
         ALOGW("Could not load the app successfully ! Unexpected failure");
         *appInstanceHandle = INVALID_APP_ID;
@@ -739,24 +793,6 @@
     return true;
 }
 
-static void invalidateNanoApps(uint32_t hubHandle) {
-    JNIEnv *env;
-
-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
-        ALOGW("Could not attach to JVM !");
-        env = nullptr;
-    }
-
-    auto end = db.appInstances.end();
-    for (auto current = db.appInstances.begin(); current != end; ) {
-        app_instance_info_s info = current->second;
-        current++;
-        if (info.hubHandle == hubHandle) {
-             delete_app_instance(info.instanceId, env);
-        }
-    }
-}
-
 static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
                              const uint8_t *msg, int msgLen) {
     int retVal = -1;
@@ -824,8 +860,7 @@
               ALOGW("Context Hub handle %d restarted", hubHandle);
               closeTxn();
               passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
-              invalidateNanoApps(hubHandle);
-              query_hub_for_apps(ALL_APPS, hubHandle);
+              query_hub_for_apps(hubHandle);
               retVal = 0;
           }
           break;
@@ -1157,7 +1192,8 @@
     if (retVal != 0) {
         ALOGD("Send Message failure - %d", retVal);
         if (msgType == CONTEXT_HUB_LOAD_APP) {
-            closeLoadTxn(false, nullptr);
+            jint ignored;
+            closeLoadTxn(false, &ignored);
         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
             closeUnloadTxn(false);
         }
diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml
index 77883d9..5cc9559 100644
--- a/core/res/res/color/hint_foreground_material_dark.xml
+++ b/core/res/res/color/hint_foreground_material_dark.xml
@@ -15,6 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+          android:state_pressed="true"
+          android:alpha="@dimen/hint_pressed_alpha_material_dark"
+          android:color="@color/foreground_material_dark" />
     <item android:alpha="@dimen/hint_alpha_material_dark"
           android:color="@color/foreground_material_dark" />
 </selector>
diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml
index 99168fd..f7465e0 100644
--- a/core/res/res/color/hint_foreground_material_light.xml
+++ b/core/res/res/color/hint_foreground_material_light.xml
@@ -15,6 +15,10 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+          android:state_pressed="true"
+          android:alpha="@dimen/hint_pressed_alpha_material_light"
+          android:color="@color/foreground_material_light" />
     <item android:alpha="@dimen/hint_alpha_material_light"
           android:color="@color/foreground_material_light" />
 </selector>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index a864cf3..92426c6 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -61,7 +61,10 @@
     <color name="secondary_text_default_material_dark">#b3ffffff</color>
 
     <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
-    <item name="hint_alpha_material_light" format="float" type="dimen">0.54</item>
+    <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
+
+    <item name="hint_pressed_alpha_material_dark" format="float" type="dimen">0.70</item>
+    <item name="hint_pressed_alpha_material_light" format="float" type="dimen">0.54</item>
 
     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 55a87ee..004b31f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2540,4 +2540,12 @@
         <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
         <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
     </string-array>
+    <!-- This config is holding calling number conversion map - expected to convert to emergency
+         number. Formats for this config as below:
+         <item>[dialstring1],[dialstring2],[dialstring3]:[replacement]</item>
+
+         E.g. for Taiwan Type Approval, 110 and 119 should be converted to 112.
+         <item>110,119:112</item>
+    -->
+    <string-array translatable="false" name="config_convert_to_emergency_number_map" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 624d547..39f20c2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4359,6 +4359,9 @@
     <string name="language_picker_section_suggested">Suggested</string>
     <!-- List section subheader for the language picker, containing a list of all languages available [CHAR LIMIT=30] -->
     <string name="language_picker_section_all">All languages</string>
+    <!-- List section subheader for the region picker, containing a list of all regions supported for the selected language.
+    Warning: this is a more 'neutral' term for 'country', not for the sub-divisions of a country. [CHAR LIMIT=30] -->
+    <string name="region_picker_section_all">All regions</string>
 
     <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
     <string name="locale_search_menu">Search</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 538f3bf..39127a4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2508,6 +2508,7 @@
   <java-symbol type="menu" name="language_selection_list" />
   <java-symbol type="string" name="country_selection_title" />
   <java-symbol type="string" name="language_picker_section_all" />
+  <java-symbol type="string" name="region_picker_section_all" />
   <java-symbol type="string" name="language_picker_section_suggested" />
   <java-symbol type="string" name="language_selection_title" />
   <java-symbol type="string" name="search_language_hint" />
@@ -2698,4 +2699,5 @@
 
   <java-symbol type="drawable" name="ic_restart" />
 
+  <java-symbol type="array" name="config_convert_to_emergency_number_map" />
 </resources>
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index d75562d..7e7c2de 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -1,6 +1,8 @@
 # For information about this file's format, see
 # https://developers.google.com/internal/publishing/redirects
 redirects:
+- from: /guide/topics/fundamentals/fragments.html
+  to: /guide/components/fragments.html
 - from: /about/versions/index.html
   to: /about/index.html
 - from: /about/versions/api-levels.html
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index dfc30c3..f3469b4 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -156,6 +156,16 @@
     "lang":"en"
   },
   {
+    "title":"GPU Debugger",
+    "summary":"Use the GPU Debugger to analyze and debug your OpenGL ES apps. Inspect the GPU state and understand what caused a specific rendering outcome.",
+    "url":"studio/debug/am-gpu-debugger.html",
+    "image":"images/tools/thumbnails/am-gpu-debugger_2-2_2x.png",
+    "type":"tools",
+    "keywords": ["android","performance","profiling","tools","monitor","debug"],
+    "tags": ["android","performance","profiling","tools","monitor","debug"],
+    "lang":"en"
+  },
+  {
     "title":"HPROF Viewer and Analyzer",
     "summary":"Use the Memory Monitor to dump the Java heap to an HPROF file. The HPROF Viewer displays classes, instances of each class, and a reference tree to help you track memory usage and find memory leaks.",
     "url":"studio/profile/am-hprof.html",
@@ -5453,6 +5463,12 @@
        "studio/profile/am-sysinfo.html"
     ]
   },
+"tools/help/gpu": {
+    "title": "",
+    "resources": [
+       "studio/debug/am-gpu-debugger.html"
+    ]
+  },
   "tools/help/shot": {
     "title": "",
     "resources": [
diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
index 4b743d5..8947baa 100644
--- a/docs/html/topic/libraries/support-library/revisions.jd
+++ b/docs/html/topic/libraries/support-library/revisions.jd
@@ -2912,8 +2912,6 @@
         <ul>
           <li>Added {@link android.support.v7.widget.GridLayout} to provide support for the
             {@link android.widget.GridLayout} layout object.</li>
-          <li>Added {@link android.support.v7.widget.Space} which can be used to create blank areas
-            within a {@link android.support.v7.widget.GridLayout} layout object.</li>
         </ul>
     </dl>
   </div>
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 27193b7..abef66f 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -36,6 +36,29 @@
 
 namespace android {
 
+// --- WeakLooperCallback ---
+
+class WeakLooperCallback: public LooperCallback {
+protected:
+    virtual ~WeakLooperCallback() { }
+
+public:
+    WeakLooperCallback(const wp<LooperCallback>& callback) :
+        mCallback(callback) {
+    }
+
+    virtual int handleEvent(int fd, int events, void* data) {
+        sp<LooperCallback> callback = mCallback.promote();
+        if (callback != NULL) {
+            return callback->handleEvent(fd, events, data);
+        }
+        return 0; // the client is gone, remove the callback
+    }
+
+private:
+    wp<LooperCallback> mCallback;
+};
+
 // --- PointerController ---
 
 // Time to wait before starting the fade when the pointer is inactive.
@@ -57,10 +80,11 @@
         const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
     mHandler = new WeakMessageHandler(this);
+    mCallback = new WeakLooperCallback(this);
 
     if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
         mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
-                       Looper::EVENT_INPUT, this, nullptr);
+                       Looper::EVENT_INPUT, mCallback, nullptr);
     } else {
         ALOGE("Failed to initialize DisplayEventReceiver.");
     }
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 99292d7..4794f3d 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -144,6 +144,7 @@
     sp<Looper> mLooper;
     sp<SpriteController> mSpriteController;
     sp<WeakMessageHandler> mHandler;
+    sp<LooperCallback> mCallback;
 
     DisplayEventReceiver mDisplayEventReceiver;
 
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index d714672..471fa2c 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -133,6 +133,10 @@
                 }
                 try {
                     mContext.unbindService(this);
+                    if (mClient instanceof ClientProxy) {
+                        mClient = null;
+                    }
+                    mService = null;
                 } catch (IllegalArgumentException ex) {
                     if (false) {
                         Log.v(TAG, "disconnect failed: " + ex);
@@ -205,6 +209,7 @@
         void scanNextPath() {
             if (mNextPath >= mPaths.length) {
                 mConnection.disconnect();
+                mConnection = null;
                 return;
             }
             String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index ae8938d..728d98f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -341,8 +341,18 @@
 
         // Fall back to traditional VIEW action...
         intent = new Intent(Intent.ACTION_VIEW);
-        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        intent.setData(doc.derivedUri);
+        intent.setDataAndType(doc.derivedUri, doc.mimeType);
+
+        // Downloads has traditionally added the WRITE permission
+        // in the TrampolineActivity. Since this behavior is long
+        // established, we set the same permission for non-managed files
+        // This ensures consistent behavior between the Downloads root
+        // and other roots.
+        int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
+        if (doc.isWriteSupported()) {
+            flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+        }
+        intent.setFlags(flags);
 
         if (DEBUG && intent.getClipData() != null) {
             Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData());
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 3a86a51..63f66de 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -235,6 +235,10 @@
         return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0;
     }
 
+    public boolean isWriteSupported() {
+        return (flags & Document.FLAG_SUPPORTS_WRITE) != 0;
+    }
+
     public boolean isDeleteSupported() {
         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
index a99e668..af8fd4c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java
@@ -23,6 +23,7 @@
 import android.hardware.display.DisplayManager;
 import android.os.AsyncTask;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.MathUtils;
@@ -207,39 +208,41 @@
 
     /**
      * Asynchronously applies display density changes to the specified display.
+     * <p>
+     * The change will be applied to the user specified by the value of
+     * {@link UserHandle#myUserId()} at the time the method is called.
      *
      * @param displayId the identifier of the display to modify
      */
     public static void clearForcedDisplayDensity(final int displayId) {
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-                    wm.clearForcedDisplayDensity(displayId);
-                } catch (RemoteException exc) {
-                    Log.w(LOG_TAG, "Unable to clear forced display density setting");
-                }
+        final int userId = UserHandle.myUserId();
+        AsyncTask.execute(() -> {
+            try {
+                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                wm.clearForcedDisplayDensityForUser(displayId, userId);
+            } catch (RemoteException exc) {
+                Log.w(LOG_TAG, "Unable to clear forced display density setting");
             }
         });
     }
 
     /**
      * Asynchronously applies display density changes to the specified display.
+     * <p>
+     * The change will be applied to the user specified by the value of
+     * {@link UserHandle#myUserId()} at the time the method is called.
      *
      * @param displayId the identifier of the display to modify
      * @param density the density to force for the specified display
      */
     public static void setForcedDisplayDensity(final int displayId, final int density) {
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-                    wm.setForcedDisplayDensity(displayId, density);
-                } catch (RemoteException exc) {
-                    Log.w(LOG_TAG, "Unable to save forced display density setting");
-                }
+        final int userId = UserHandle.myUserId();
+        AsyncTask.execute(() -> {
+            try {
+                final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                wm.setForcedDisplayDensityForUser(displayId, density, userId);
+            } catch (RemoteException exc) {
+                Log.w(LOG_TAG, "Unable to save forced display density setting");
             }
         });
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a50b366..458672a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -28,6 +28,8 @@
 import android.content.res.TypedArray;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.support.v4.widget.DrawerLayout;
 import android.util.ArraySet;
@@ -73,6 +75,7 @@
     private FrameLayout mContentHeaderContainer;
     private DrawerLayout mDrawerLayout;
     private boolean mShowingMenu;
+    private UserManager mUserManager;
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -110,6 +113,8 @@
                 onTileClicked(mDrawerAdapter.getTile(position));
             };
         });
+
+        mUserManager = UserManager.get(this);
         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
                 + " ms");
     }
@@ -257,6 +262,7 @@
             return true;
         }
         try {
+            updateUserHandlesIfNeeded(tile);
             int numUserHandles = tile.userHandle.size();
             if (numUserHandles > 1) {
                 ProfileSelectDialog.show(getFragmentManager(), tile);
@@ -278,6 +284,19 @@
         return true;
     }
 
+    private void updateUserHandlesIfNeeded(Tile tile) {
+        List<UserHandle> userHandles = tile.userHandle;
+
+        for (int i = userHandles.size()-1; i >= 0; i--) {
+            if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) {
+                if (DEBUG_TIMING) {
+                    Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
+                }
+                userHandles.remove(i);
+            }
+        }
+    }
+
     protected void onTileClicked(Tile tile) {
         if (openTile(tile)) {
             finish();
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index b9ae585..19ae295 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -49,7 +49,6 @@
         Key.QS_WORK_ADDED,
     })
     public @interface Key {
-        @Deprecated
         String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime";
         String DEBUG_MODE_ENABLED = "debugModeEnabled";
         String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index a7d7df5..7207463 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -34,7 +34,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -47,7 +46,6 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
@@ -252,19 +250,6 @@
             registerWithSystemUser();
         }
         putComponent(Recents.class, this);
-
-        // Migrate the old stack active time if necessary, otherwise, it will already be managed
-        // when the tasks are loaded in the system. See TaskPersister.restoreTasksForUserLocked().
-        long lastVisibleTaskActiveTime = Prefs.getLong(mContext,
-                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
-        if (lastVisibleTaskActiveTime != -1) {
-            long uptime = SystemClock.elapsedRealtime();
-            Settings.Secure.putLongForUser(mContext.getContentResolver(),
-                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
-                    uptime - Math.max(0, System.currentTimeMillis() - lastVisibleTaskActiveTime),
-                    processUser);
-            Prefs.remove(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME);
-        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 1e41870..7bdb1c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -20,7 +20,6 @@
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -171,6 +170,13 @@
             if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 // When the screen turns off, dismiss Recents to Home
                 dismissRecentsToHomeIfVisible(false);
+            } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
+                // For the time being, if the time changes, then invalidate the
+                // last-stack-active-time, this ensures that we will just show the last N tasks
+                // the next time that Recents loads, but prevents really old tasks from showing
+                // up if the task time is set forward.
+                Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
+                        0);
             }
         }
     };
@@ -316,6 +322,7 @@
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(Intent.ACTION_TIME_CHANGED);
         registerReceiver(mSystemBroadcastReceiver, filter);
 
         getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
@@ -793,19 +800,14 @@
         EventBus.getDefault().dump(prefix, writer);
         Recents.getTaskLoader().dump(prefix, writer);
 
-        ContentResolver cr = getContentResolver();
-        long lastPersistUptime = Settings.Secure.getLong(cr,
-                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0);
-        long lastVisibleTaskActiveUptime = Settings.Secure.getLongForUser(cr,
-                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
-                SystemClock.elapsedRealtime(), Recents.getSystemServices().getCurrentUser());
-
         String id = Integer.toHexString(System.identityHashCode(this));
+        long lastStackActiveTime = Prefs.getLong(this,
+                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
 
         writer.print(prefix); writer.print(TAG);
         writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N");
-        writer.print(" lastPersistUptime="); writer.print(lastPersistUptime);
-        writer.print(" lastVisibleTaskActiveUptime="); writer.print(lastVisibleTaskActiveUptime);
+        writer.print(" lastStackTaskActiveTime="); writer.print(lastStackActiveTime);
+        writer.print(" currentTime="); writer.print(System.currentTimeMillis());
         writer.print(" [0x"); writer.print(id); writer.print("]");
         writer.println();
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 0dd9e54..b896f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -59,7 +59,6 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -75,7 +74,6 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.os.BackgroundThread;
 import com.android.systemui.R;
@@ -200,9 +198,6 @@
      */
     private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
 
-    /** Test constructor */
-    @VisibleForTesting public SystemServicesProxy() {}
-
     /** Private constructor */
     private SystemServicesProxy(Context context) {
         mAccm = AccessibilityManager.getInstance(context);
@@ -304,7 +299,7 @@
                 rti.baseIntent = new Intent();
                 rti.baseIntent.setComponent(cn);
                 rti.description = description;
-                rti.firstActiveTime = rti.lastActiveTime = SystemClock.elapsedRealtime();
+                rti.firstActiveTime = rti.lastActiveTime = i;
                 if (i % 2 == 0) {
                     rti.taskDescription = new ActivityManager.TaskDescription(description,
                         Bitmap.createBitmap(mDummyIcon), null,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index ecd48e1..1278b73 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -24,15 +24,13 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -58,11 +56,6 @@
     private static int SESSION_BEGIN_TIME = 1000 /* ms/s */ * 60 /* s/min */ * 60 /* min/hr */ *
             6 /* hrs */;
 
-    @VisibleForTesting
-    public interface SystemTimeProvider {
-        public long getTime();
-    }
-
     /** The set of conditions to load tasks. */
     public static class Options {
         public int runningTaskId = -1;
@@ -74,46 +67,15 @@
         public int numVisibleTaskThumbnails = 0;
     }
 
-    private Context mContext;
-    @VisibleForTesting private SystemServicesProxy mSystemServicesProxy;
+    Context mContext;
 
-    private List<ActivityManager.RecentTaskInfo> mRawTasks;
-    private long mLastVisibileTaskActiveTime;
-    private TaskStack mStack;
-    private ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
-    private SystemTimeProvider mTimeProvider = new SystemTimeProvider() {
-        @Override
-        public long getTime() {
-            return SystemClock.elapsedRealtime();
-        }
-    };
+    List<ActivityManager.RecentTaskInfo> mRawTasks;
+    TaskStack mStack;
+    ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>();
 
-    @VisibleForTesting
-    public RecentsTaskLoadPlan(Context context, SystemServicesProxy ssp) {
+    /** Package level ctor */
+    RecentsTaskLoadPlan(Context context) {
         mContext = context;
-        mSystemServicesProxy = ssp;
-    }
-
-    @VisibleForTesting
-    public void setInternals(List<ActivityManager.RecentTaskInfo> tasks,
-            final long currentTime, long lastVisibleTaskActiveTime) {
-        setInternals(tasks, MIN_NUM_TASKS, currentTime, lastVisibleTaskActiveTime,
-                SESSION_BEGIN_TIME);
-    }
-
-    @VisibleForTesting
-    public void setInternals(List<ActivityManager.RecentTaskInfo> tasks, int minNumTasks,
-            final long currentTime, long lastVisibleTaskActiveTime,  int sessionBeginTime) {
-        mRawTasks = tasks;
-        mLastVisibileTaskActiveTime = lastVisibleTaskActiveTime;
-        mTimeProvider = new SystemTimeProvider() {
-            @Override
-            public long getTime() {
-                return currentTime;
-            }
-        };
-        MIN_NUM_TASKS = minNumTasks;
-        SESSION_BEGIN_TIME = sessionBeginTime;
     }
 
     private void updateCurrentQuietProfilesCache(int currentUserId) {
@@ -141,13 +103,9 @@
     public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) {
         int currentUserId = UserHandle.USER_CURRENT;
         updateCurrentQuietProfilesCache(currentUserId);
-        mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles);
-        mLastVisibileTaskActiveTime = RecentsDebugFlags.Static.EnableMockTasks
-                ? SystemClock.elapsedRealtime()
-                : Settings.Secure.getLongForUser(mContext.getContentResolver(),
-                        Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
-                                0, currentUserId);
 
         // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
         Collections.reverse(mRawTasks);
@@ -176,9 +134,12 @@
                 R.string.accessibility_recents_item_will_be_dismissed);
         String appInfoDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_open_app_info);
-        boolean updatedLastVisibleTaskActiveTime = false;
-        long newLastVisibileTaskActiveTime = 0;
-        long currentTime = mTimeProvider.getTime();
+        long lastStackActiveTime = Prefs.getLong(mContext,
+                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            lastStackActiveTime = 0;
+        }
+        long newLastStackActiveTime = -1;
         int taskCount = mRawTasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
@@ -187,20 +148,19 @@
             Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
                     t.userId, t.firstActiveTime, t.lastActiveTime);
 
-            // Only show the task if it is freeform, or later than the last visible task active time
-            // and either recently used, or within the last five tasks
-            boolean isFreeformTask = mSystemServicesProxy.isFreeformStack(t.stackId);
-            boolean isRecentlyUsedTask = t.lastActiveTime >= (currentTime - SESSION_BEGIN_TIME);
-            boolean isMoreRecentThanLastVisible = t.lastActiveTime >= mLastVisibileTaskActiveTime;
-            boolean isStackTask = isFreeformTask || (isMoreRecentThanLastVisible &&
-                    (isRecentlyUsedTask || i >= (taskCount - MIN_NUM_TASKS)));
-            boolean isLaunchTarget = t.persistentId == runningTaskId;
+            // This task is only shown in the stack if it statisfies the historical time or min
+            // number of tasks constraints. Freeform tasks are also always shown.
+            boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
+            boolean isStackTask = isFreeformTask || !isHistoricalTask(t) ||
+                    (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
+            boolean isLaunchTarget = taskKey.id == runningTaskId;
 
-            // If this is the first task satisfying the stack constraints, update the baseline
-            // at which we show visible tasks
-            if (isStackTask && !updatedLastVisibleTaskActiveTime) {
-                newLastVisibileTaskActiveTime = t.lastActiveTime;
-                updatedLastVisibleTaskActiveTime = true;
+            // The last stack active time is the baseline for which we show visible tasks.  Since
+            // the system will store all the tasks, we don't want to show the tasks prior to the
+            // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy
+            // the other stack-task constraints.
+            if (isStackTask && newLastStackActiveTime < 0) {
+                newLastStackActiveTime = t.lastActiveTime;
             }
 
             // Load the title, icon, and color
@@ -228,12 +188,9 @@
             affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
             affiliatedTasks.put(taskKey.id, taskKey);
         }
-        if (updatedLastVisibleTaskActiveTime &&
-                newLastVisibileTaskActiveTime != mLastVisibileTaskActiveTime) {
-            Settings.Secure.putLongForUser(mContext.getContentResolver(),
-                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
-                            newLastVisibileTaskActiveTime, UserHandle.USER_CURRENT);
-            mLastVisibileTaskActiveTime = newLastVisibileTaskActiveTime;
+        if (newLastStackActiveTime != -1) {
+            Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
+                    newLastStackActiveTime);
         }
 
         // Initialize the stacks
@@ -298,4 +255,11 @@
         }
         return false;
     }
+
+    /**
+     * Returns whether this task is too old to be shown.
+     */
+    private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) {
+        return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME);
+    }
 }
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 e0eda37..ba31e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -30,7 +30,6 @@
 import android.util.Log;
 import android.util.LruCache;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -287,20 +286,6 @@
         }
     };
 
-    @VisibleForTesting
-    public RecentsTaskLoader() {
-        mActivityInfoCache = null;
-        mIconCache = null;
-        mThumbnailCache = null;
-        mActivityLabelCache = null;
-        mContentDescriptionCache = null;
-        mLoadQueue = null;
-        mLoader = null;
-
-        mMaxThumbnailCacheSize = 0;
-        mMaxIconCacheSize = 0;
-    }
-
     public RecentsTaskLoader(Context context) {
         Resources res = context.getResources();
         mDefaultTaskBarBackgroundColor =
@@ -347,8 +332,7 @@
 
     /** Creates a new plan for loading the recent tasks. */
     public RecentsTaskLoadPlan createLoadPlan(Context context) {
-        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context,
-                Recents.getSystemServices());
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context);
         return plan;
     }
 
@@ -471,8 +455,7 @@
     /**
      * Returns the cached task label if the task key is not expired, updating the cache if it is.
      */
-    @VisibleForTesting public String getAndUpdateActivityTitle(Task.TaskKey taskKey,
-            ActivityManager.TaskDescription td) {
+    String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the task description label if it exists
@@ -500,8 +483,7 @@
      * Returns the cached task content description if the task key is not expired, updating the
      * cache if it is.
      */
-    @VisibleForTesting public String getAndUpdateContentDescription(Task.TaskKey taskKey,
-            Resources res) {
+    String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached content description if it exists
@@ -525,8 +507,8 @@
     /**
      * Returns the cached task icon if the task key is not expired, updating the cache if it is.
      */
-    @VisibleForTesting public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
-            ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) {
+    Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
+            Resources res, boolean loadIfNotCached) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached activity icon if it exists
@@ -560,8 +542,7 @@
     /**
      * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
      */
-    @VisibleForTesting public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey,
-            boolean loadIfNotCached) {
+    Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Return the cached thumbnail if it exists
@@ -589,7 +570,7 @@
      * Returns the task's primary color if possible, defaulting to the default color if there is
      * no specified primary color.
      */
-    @VisibleForTesting public int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
+    int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
         if (td != null && td.getPrimaryColor() != 0) {
             return td.getPrimaryColor();
         }
@@ -599,7 +580,7 @@
     /**
      * Returns the task's background color if possible.
      */
-    @VisibleForTesting public int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
+    int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
         if (td != null && td.getBackgroundColor() != 0) {
             return td.getBackgroundColor();
         }
@@ -610,7 +591,7 @@
      * Returns the activity info for the given task key, retrieving one from the system if the
      * task key is expired.
      */
-    @VisibleForTesting public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+    ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         ComponentName cn = taskKey.getComponent();
         ActivityInfo activityInfo = mActivityInfoCache.get(cn);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 4191f52..86a0315 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -290,10 +290,7 @@
      */
     public boolean isFreeformTask() {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp != null) {
-            return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId);
-        }
-        return false;
+        return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId);
     }
 
     /** Notifies the callback listeners that this task has been loaded */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 93ed139..41b0bb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -308,6 +308,7 @@
         super.setVisibility(visibility);
         if (visibility != View.VISIBLE) {
             mSystemIconsSuperContainer.animate().cancel();
+            mSystemIconsSuperContainer.setTranslationX(0);
             mMultiUserSwitch.animate().cancel();
             mMultiUserSwitch.setAlpha(1f);
         } else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java
deleted file mode 100644
index dd78595..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2016 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.systemui.recents;
-
-import android.app.ActivityManager;
-import android.content.pm.ActivityInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-
-import java.util.ArrayList;
-
-/**
- * Mock task loader that does not actually load any tasks.
- */
-class MockRecentsTaskNonLoader extends RecentsTaskLoader {
-    @Override
-    public String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
-        return "";
-    }
-
-    @Override
-    public String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) {
-        return "";
-    }
-
-    @Override
-    public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) {
-        return null;
-    }
-
-    @Override
-    public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
-        return null;
-    }
-
-    @Override
-    public int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
-        return 0;
-    }
-
-    @Override
-    public int getActivityBackgroundColor(ActivityManager.TaskDescription td) {
-        return 0;
-    }
-
-    @Override
-    public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
-        return null;
-    }
-}
-
-/**
- * TODO(winsonc):
- * - add test to ensure excluded tasks are loaded at the front of the list
- * - add test to ensure the last visible task active time is migrated from absolute to uptime
- */
-public class RecentsTaskLoadPlanTest extends SysuiTestCase {
-    private static final String TAG = "RecentsTaskLoadPlanTest";
-
-    private MockRecentsTaskNonLoader mDummyLoader = new MockRecentsTaskNonLoader();
-    private SystemServicesProxy mDummySsp = new SystemServicesProxy();
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    public void testEmptyRecents() {
-        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getTestContext(), mDummySsp);
-        ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>();
-        loadPlan.setInternals(tasks, 0 /* current */, 0 /* lastVisibleTaskActive */);
-        loadPlan.preloadPlan(mDummyLoader, 0 /* runningTaskId */,
-                false /* includeFrontMostExcludedTask */);
-        assertFalse("Expected task to be empty", loadPlan.getTaskStack().getStackTaskCount() > 0);
-    }
-
-    public void testLessThanEqualMinTasks() {
-        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getTestContext(), mDummySsp);
-        ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>();
-        int minTasks = 3;
-
-        resetTaskInfoList(tasks,
-                createTaskInfo(0, 1),
-                createTaskInfo(1, 2),
-                createTaskInfo(2, 3));
-
-        // Ensure that all tasks are loaded if the tasks are within the session and after the last
-        // visible active time (all tasks are loaded because there are < minTasks number of tasks)
-        loadPlan.setInternals(tasks, minTasks, 0 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */,
-                0 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 3 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 3 /* current */, 1 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        // Ensure that only tasks are not loaded if are after the last visible active time, even if
-        // they are within the session
-        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 1 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 2 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
-        assertTasksInStack(loadPlan.getTaskStack(), 1, 2);
-
-        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 3 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
-        assertTasksInStack(loadPlan.getTaskStack(), 2);
-
-        loadPlan.setInternals(tasks, minTasks, 50 /* current */, 50 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
-    }
-
-    public void testMoreThanMinTasks() {
-        RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getTestContext(), mDummySsp);
-        ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>();
-        int minTasks = 3;
-
-        // Create all tasks within the session
-        resetTaskInfoList(tasks,
-                createTaskInfo(0, 1),
-                createTaskInfo(1, 50),
-                createTaskInfo(2, 100),
-                createTaskInfo(3, 101),
-                createTaskInfo(4, 102),
-                createTaskInfo(5, 103));
-
-        // Ensure that only the tasks that are within the window but after the last visible active
-        // time is loaded, or the minTasks number of tasks are loaded if there are less than that
-
-        // Session window shifts
-        loadPlan.setInternals(tasks, minTasks, 0 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 51 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 52 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
-        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 100 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
-        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 101 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
-        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 103 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
-        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
-        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 151 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
-        assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 200 /* current */, 0 /* lastVisibleTaskActive */,
-                50 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
-        assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5);
-
-        // Last visible active time shifts (everything is in window)
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 1 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 2 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
-        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 50 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0);
-        assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 51 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
-        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 100 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1);
-        assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 101 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2);
-        assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 102 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3);
-        assertTasksInStack(loadPlan.getTaskStack(), 4, 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 103 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4);
-        assertTasksInStack(loadPlan.getTaskStack(), 5);
-
-        loadPlan.setInternals(tasks, minTasks, 150 /* current */, 104 /* lastVisibleTaskActive */,
-                150 /* sessionBegin */);
-        loadPlan.preloadPlan(mDummyLoader, 0, false);
-        assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5);
-    }
-
-    private ActivityManager.RecentTaskInfo createTaskInfo(int taskId, long lastActiveTime) {
-        ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
-        info.id = info.persistentId = taskId;
-        info.lastActiveTime = lastActiveTime;
-        return info;
-    }
-
-    private void resetTaskInfoList(ArrayList<ActivityManager.RecentTaskInfo> tasks,
-            ActivityManager.RecentTaskInfo ... infos) {
-        tasks.clear();
-        for (ActivityManager.RecentTaskInfo info : infos) {
-            tasks.add(info);
-        }
-    }
-
-    private void assertTasksInStack(TaskStack stack, int... taskIds) {
-        for (int taskId : taskIds) {
-            assertNotNull("Expected task " + taskId + " in stack", stack.findTaskWithId(taskId));
-        }
-    }
-
-    private void assertTasksNotInStack(TaskStack stack, int... taskIds) {
-        for (int taskId : taskIds) {
-            assertNull("Expected task " + taskId + " not in stack", stack.findTaskWithId(taskId));
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 71ac544..8ae4917 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -822,7 +822,7 @@
         public void onUnlockUser(final @UserIdInt int userHandle) {
             // Called on ActivityManager thread.
             mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
-                    userHandle));
+                    userHandle /* arg1 */, 0 /* arg2 */));
         }
     }
 
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 3fdcceb..83d374c 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -364,6 +364,7 @@
             buildResolveList(intent, categories, debug, defaultOnly,
                     resolvedType, scheme, listCut.get(i), resultList, userId);
         }
+        filterResults(resultList);
         sortResults(resultList);
         return resultList;
     }
@@ -457,6 +458,7 @@
             buildResolveList(intent, categories, debug, defaultOnly,
                     resolvedType, scheme, schemeCut, finalList, userId);
         }
+        filterResults(finalList);
         sortResults(finalList);
 
         if (debug) {
@@ -521,6 +523,12 @@
         Collections.sort(results, mResolvePrioritySorter);
     }
 
+    /**
+     * Apply filtering to the results. This happens before the results are sorted.
+     */
+    protected void filterResults(List<R> results) {
+    }
+
     protected void dumpFilter(PrintWriter out, String prefix, F filter) {
         out.print(prefix); out.println(filter);
     }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
new file mode 100644
index 0000000..087ec61
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PackageUtils;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for backup and restore of account access grants.
+ */
+public final class AccountManagerBackupHelper {
+    private static final String TAG = "AccountManagerBackupHelper";
+
+    private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+
+    private static final String TAG_PERMISSIONS = "permissions";
+    private static final String TAG_PERMISSION = "permission";
+    private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256";
+    private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_DIGEST = "digest";
+
+    private static final String ACCOUNT_ACCESS_GRANTS = ""
+            + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", "
+            + AccountManagerService.GRANTS_GRANTEE_UID
+            + " FROM " + AccountManagerService.TABLE_ACCOUNTS
+            + ", " + AccountManagerService.TABLE_GRANTS
+            + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID
+            + "=" + AccountManagerService.ACCOUNTS_ID;
+
+    private final Object mLock = new Object();
+
+    private final AccountManagerService mAccountManagerService;
+    private final AccountManagerInternal mAccountManagerInternal;
+
+    @GuardedBy("mLock")
+    private List<PendingAppPermission> mRestorePendingAppPermissions;
+
+    @GuardedBy("mLock")
+    private RestorePackageMonitor mRestorePackageMonitor;
+
+    @GuardedBy("mLock")
+    private Runnable mRestoreCancelCommand;
+
+    public AccountManagerBackupHelper(AccountManagerService accountManagerService,
+            AccountManagerInternal accountManagerInternal) {
+        mAccountManagerService = accountManagerService;
+        mAccountManagerInternal = accountManagerInternal;
+    }
+
+    private final class PendingAppPermission {
+        private final @NonNull String accountDigest;
+        private final @NonNull String packageName;
+        private final @NonNull String certDigest;
+        private final @IntRange(from = 0) int userId;
+
+        public PendingAppPermission(String accountDigest, String packageName,
+                String certDigest, int userId) {
+            this.accountDigest = accountDigest;
+            this.packageName = packageName;
+            this.certDigest = certDigest;
+            this.userId = userId;
+        }
+
+        public boolean apply(PackageManager packageManager) {
+            Account account = null;
+            AccountManagerService.UserAccounts accounts = mAccountManagerService
+                    .getUserAccounts(userId);
+            synchronized (accounts.cacheLock) {
+                for (Account[] accountsPerType : accounts.accountCache.values()) {
+                    for (Account accountPerType : accountsPerType) {
+                        if (accountDigest.equals(PackageUtils.computeSha256Digest(
+                                accountPerType.name.getBytes()))) {
+                            account = accountPerType;
+                            break;
+                        }
+                    }
+                    if (account != null) {
+                        break;
+                    }
+                }
+            }
+            if (account == null) {
+                return false;
+            }
+            final PackageInfo packageInfo;
+            try {
+                packageInfo = packageManager.getPackageInfoAsUser(packageName,
+                        PackageManager.GET_SIGNATURES, userId);
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+            String currentCertDigest = PackageUtils.computeCertSha256Digest(
+                    packageInfo.signatures[0]);
+            if (!certDigest.equals(currentCertDigest)) {
+                return false;
+            }
+            final int uid = packageInfo.applicationInfo.uid;
+            if (!mAccountManagerInternal.hasAccountAccess(account, uid)) {
+                mAccountManagerService.grantAppPermission(account,
+                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid);
+            }
+            return true;
+        }
+    }
+
+    public byte[] backupAccountAccessPermissions(int userId) {
+        final AccountManagerService.UserAccounts accounts = mAccountManagerService
+                .getUserAccounts(userId);
+        synchronized (accounts.cacheLock) {
+            SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+            try (
+                Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null);
+            ) {
+                if (cursor == null || !cursor.moveToFirst()) {
+                    return null;
+                }
+
+                final int nameColumnIdx = cursor.getColumnIndex(
+                        AccountManagerService.ACCOUNTS_NAME);
+                final int uidColumnIdx = cursor.getColumnIndex(
+                        AccountManagerService.GRANTS_GRANTEE_UID);
+
+                ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+                try {
+                    final XmlSerializer serializer = new FastXmlSerializer();
+                    serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
+                    serializer.startDocument(null, true);
+                    serializer.startTag(null, TAG_PERMISSIONS);
+
+                    PackageManager packageManager = mAccountManagerService.mContext
+                            .getPackageManager();
+
+                    do {
+                        final String accountName = cursor.getString(nameColumnIdx);
+                        final int uid = cursor.getInt(uidColumnIdx);
+
+                        final String[] packageNames = packageManager.getPackagesForUid(uid);
+                        if (packageNames == null) {
+                            continue;
+                        }
+
+                        for (String packageName : packageNames) {
+                            String digest = PackageUtils.computePackageCertSha256Digest(
+                                    packageManager, packageName, userId);
+                            if (digest != null) {
+                                serializer.startTag(null, TAG_PERMISSION);
+                                serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
+                                        PackageUtils.computeSha256Digest(accountName.getBytes()));
+                                serializer.attribute(null, ATTR_PACKAGE, packageName);
+                                serializer.attribute(null, ATTR_DIGEST, digest);
+                                serializer.endTag(null, TAG_PERMISSION);
+                            }
+                        }
+                    } while (cursor.moveToNext());
+
+                    serializer.endTag(null, TAG_PERMISSIONS);
+                    serializer.endDocument();
+                    serializer.flush();
+                } catch (IOException e) {
+                    Log.e(TAG, "Error backing up account access grants", e);
+                    return null;
+                }
+
+                return dataStream.toByteArray();
+            }
+        }
+    }
+
+    public void restoreAccountAccessPermissions(byte[] data, int userId) {
+        try {
+            ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(dataStream, StandardCharsets.UTF_8.name());
+            PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
+
+            final int permissionsOuterDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) {
+                if (!TAG_PERMISSIONS.equals(parser.getName())) {
+                    continue;
+                }
+                final int permissionOuterDepth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) {
+                    if (!TAG_PERMISSION.equals(parser.getName())) {
+                        continue;
+                    }
+                    String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256);
+                    if (TextUtils.isEmpty(accountDigest)) {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    if (TextUtils.isEmpty(packageName)) {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+                    String digest =  parser.getAttributeValue(null, ATTR_DIGEST);
+                    if (TextUtils.isEmpty(digest)) {
+                        XmlUtils.skipCurrentTag(parser);
+                    }
+
+                    PendingAppPermission pendingAppPermission = new PendingAppPermission(
+                            accountDigest, packageName, digest, userId);
+
+                    if (!pendingAppPermission.apply(packageManager)) {
+                        synchronized (mLock) {
+                            // Start watching before add pending to avoid a missed signal
+                            if (mRestorePackageMonitor == null) {
+                                mRestorePackageMonitor = new RestorePackageMonitor();
+                                mRestorePackageMonitor.register(mAccountManagerService.mContext,
+                                        mAccountManagerService.mMessageHandler.getLooper(), true);
+                            }
+                            if (mRestorePendingAppPermissions == null) {
+                                mRestorePendingAppPermissions = new ArrayList<>();
+                            }
+                            mRestorePendingAppPermissions.add(pendingAppPermission);
+                        }
+                    }
+                }
+            }
+
+            // Make sure we eventually prune the in-memory pending restores
+            mRestoreCancelCommand = new CancelRestoreCommand();
+            mAccountManagerService.mMessageHandler.postDelayed(mRestoreCancelCommand,
+                    PENDING_RESTORE_TIMEOUT_MILLIS);
+        } catch (XmlPullParserException | IOException e) {
+            Log.e(TAG, "Error restoring app permissions", e);
+        }
+    }
+
+    private final class RestorePackageMonitor extends PackageMonitor {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            synchronized (mLock) {
+                if (mRestorePendingAppPermissions == null) {
+                    return;
+                }
+                if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
+                    return;
+                }
+                final int count = mRestorePendingAppPermissions.size();
+                for (int i = count - 1; i >= 0; i--) {
+                    PendingAppPermission pendingAppPermission =
+                            mRestorePendingAppPermissions.get(i);
+                    if (!pendingAppPermission.packageName.equals(packageName)) {
+                        continue;
+                    }
+                    if (pendingAppPermission.apply(
+                            mAccountManagerService.mContext.getPackageManager())) {
+                        mRestorePendingAppPermissions.remove(i);
+                    }
+                }
+                if (mRestorePendingAppPermissions.isEmpty()
+                        && mRestoreCancelCommand != null) {
+                    mAccountManagerService.mMessageHandler.removeCallbacks(mRestoreCancelCommand);
+                    mRestoreCancelCommand.run();
+                    mRestoreCancelCommand = null;
+                }
+            }
+        }
+    }
+
+    private final class CancelRestoreCommand implements Runnable {
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                mRestorePendingAppPermissions = null;
+                if (mRestorePackageMonitor != null) {
+                    mRestorePackageMonitor.unregister();
+                    mRestorePackageMonitor = null;
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2f96b20..da890c8 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -26,12 +26,14 @@
 import android.accounts.AuthenticatorDescription;
 import android.accounts.CantAddAccountActivity;
 import android.accounts.GrantCredentialsPermissionActivity;
+import android.accounts.IAccountAccessTracker;
 import android.accounts.IAccountAuthenticator;
 import android.accounts.IAccountAuthenticatorResponse;
 import android.accounts.IAccountManager;
 import android.accounts.IAccountManagerResponse;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
@@ -85,15 +87,16 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
-import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.PackageUtils;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
@@ -125,6 +128,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -155,13 +159,6 @@
         }
 
         @Override
-        public void onBootPhase(int phase) {
-            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
-                mService.systemReady();
-            }
-        }
-
-        @Override
         public void onUnlockUser(int userHandle) {
             mService.onUnlockUser(userHandle);
         }
@@ -174,13 +171,13 @@
 
     private static final int MAX_DEBUG_DB_SIZE = 64;
 
-    private final Context mContext;
+    final Context mContext;
 
     private final PackageManager mPackageManager;
     private final AppOpsManager mAppOpsManager;
     private UserManager mUserManager;
 
-    private final MessageHandler mMessageHandler;
+    final MessageHandler mMessageHandler;
 
     // Messages that can be sent on mHandler
     private static final int MESSAGE_TIMED_OUT = 3;
@@ -188,9 +185,9 @@
 
     private final IAccountAuthenticatorCache mAuthenticatorCache;
 
-    private static final String TABLE_ACCOUNTS = "accounts";
-    private static final String ACCOUNTS_ID = "_id";
-    private static final String ACCOUNTS_NAME = "name";
+    static final String TABLE_ACCOUNTS = "accounts";
+    static final String ACCOUNTS_ID = "_id";
+    static final String ACCOUNTS_NAME = "name";
     private static final String ACCOUNTS_TYPE = "type";
     private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
     private static final String ACCOUNTS_PASSWORD = "password";
@@ -204,10 +201,10 @@
     private static final String AUTHTOKENS_TYPE = "type";
     private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
 
-    private static final String TABLE_GRANTS = "grants";
-    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
+    static final String TABLE_GRANTS = "grants";
+    static final String GRANTS_ACCOUNTS_ID = "accounts_id";
     private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
-    private static final String GRANTS_GRANTEE_UID = "uid";
+    static final String GRANTS_GRANTEE_UID = "uid";
 
     private static final String TABLE_EXTRAS = "extras";
     private static final String EXTRAS_ID = "_id";
@@ -274,16 +271,16 @@
 
     static class UserAccounts {
         private final int userId;
-        private final DeDatabaseHelper openHelper;
+        final DeDatabaseHelper openHelper;
         private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
                 credentialsPermissionNotificationIds =
                 new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
         private final HashMap<Account, Integer> signinRequiredNotificationIds =
                 new HashMap<Account, Integer>();
-        private final Object cacheLock = new Object();
+        final Object cacheLock = new Object();
         /** protected by the {@link #cacheLock} */
-        private final HashMap<String, Account[]> accountCache =
-                new LinkedHashMap<String, Account[]>();
+        final HashMap<String, Account[]> accountCache =
+                new LinkedHashMap<>();
         /** protected by the {@link #cacheLock} */
         private final HashMap<Account, HashMap<String, String>> userDataCache =
                 new HashMap<Account, HashMap<String, String>>();
@@ -322,6 +319,8 @@
 
     private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
     private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
+    private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
+            mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
 
     private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();
     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
@@ -502,7 +501,7 @@
         if (!checkAccess || hasAccountAccess(account, packageName,
                 UserHandle.getUserHandleForUid(uid))) {
             cancelNotification(getCredentialPermissionNotificationId(account,
-                    AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+                    AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
                     UserHandle.getUserHandleForUid(uid));
         }
     }
@@ -522,9 +521,6 @@
         }
     }
 
-    public void systemReady() {
-    }
-
     private UserManager getUserManager() {
         if (mUserManager == null) {
             mUserManager = UserManager.get(mContext);
@@ -695,7 +691,8 @@
                     final ArrayList<String> accountNames = cur.getValue();
                     final Account[] accountsForType = new Account[accountNames.size()];
                     for (int i = 0; i < accountsForType.length; i++) {
-                        accountsForType[i] = new Account(accountNames.get(i), accountType);
+                        accountsForType[i] = new Account(accountNames.get(i), accountType,
+                                new AccountAccessTracker());
                     }
                     accounts.accountCache.put(accountType, accountsForType);
                 }
@@ -1505,6 +1502,8 @@
             Bundle result = new Bundle();
             result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
             result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type);
+            result.putBinder(AccountManager.KEY_ACCOUNT_ACCESS_TRACKER,
+                    resultingAccount.getAccessTracker().asBinder());
             try {
                 response.onResult(result);
             } catch (RemoteException e) {
@@ -1857,7 +1856,7 @@
                 for (Pair<Pair<Account, String>, Integer> key
                         : accounts.credentialsPermissionNotificationIds.keySet()) {
                     if (account.equals(key.first.first)
-                            && AccountManager.ACCOUNT_ACCESS_TOKEN.equals(key.first.second)) {
+                            && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) {
                         final int uid = (Integer) key.second;
                         mMessageHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
                                 account, uid, false));
@@ -3457,22 +3456,36 @@
         Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
 
         try {
-
             final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
-            // Use null token which means any token. Having a token means the package
-            // is trusted by the authenticator, hence it is fine to access the account.
-            if (permissionIsGranted(account, null, uid, userId)) {
-                return true;
-            }
-            // In addition to the permissions required to get an auth token we also allow
-            // the account to be accessed by holders of the get accounts permissions.
-            return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
-                    || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+            return hasAccountAccess(account, packageName, uid);
         } catch (NameNotFoundException e) {
             return false;
         }
     }
 
+    private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
+            int uid) {
+        if (packageName == null) {
+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
+            if (ArrayUtils.isEmpty(packageNames)) {
+                return false;
+            }
+            // For app op checks related to permissions all packages in the UID
+            // have the same app op state, so doesn't matter which one we pick.
+            packageName = packageNames[0];
+        }
+
+        // Use null token which means any token. Having a token means the package
+        // is trusted by the authenticator, hence it is fine to access the account.
+        if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) {
+            return true;
+        }
+        // In addition to the permissions required to get an auth token we also allow
+        // the account to be accessed by holders of the get accounts permissions.
+        return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
+                || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+    }
+
     private boolean checkUidPermission(String permission, int uid, String opPackageName) {
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -3548,7 +3561,7 @@
 
             private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
                 cancelNotification(getCredentialPermissionNotificationId(account,
-                        AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName,
                         UserHandle.getUserHandleForUid(uid));
                 if (callback != null) {
                     Bundle result = new Bundle();
@@ -3556,7 +3569,7 @@
                     callback.sendResult(result);
                 }
             }
-        }), AccountManager.ACCOUNT_ACCESS_TOKEN, false);
+        }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false);
     }
 
     @Override
@@ -4432,7 +4445,7 @@
         }
     }
 
-    private class MessageHandler extends Handler {
+    class MessageHandler extends Handler {
         MessageHandler(Looper looper) {
             super(looper);
         }
@@ -5583,7 +5596,7 @@
      * which is in the system. This means we don't need to protect it with permissions.
      * @hide
      */
-    private void grantAppPermission(Account account, String authTokenType, int uid) {
+    void grantAppPermission(Account account, String authTokenType, int uid) {
         if (account == null || authTokenType == null) {
             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
             return;
@@ -5610,6 +5623,12 @@
 
             cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
         }
+
+        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+        for (AccountManagerInternal.OnAppPermissionChangeListener listener
+                : mAppPermissionChangeListeners) {
+            mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid));
+        }
     }
 
     /**
@@ -5642,9 +5661,16 @@
             } finally {
                 db.endTransaction();
             }
+
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
                     new UserHandle(accounts.userId));
         }
+
+        // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+        for (AccountManagerInternal.OnAppPermissionChangeListener listener
+                : mAppPermissionChangeListeners) {
+            mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid));
+        }
     }
 
     static final private String stringArrayToString(String[] value) {
@@ -5683,7 +5709,7 @@
         if (accountsForType != null) {
             System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
         }
-        newAccountsForType[oldLength] = account;
+        newAccountsForType[oldLength] = new Account(account, new AccountAccessTracker());
         accounts.accountCache.put(account.type, newAccountsForType);
     }
 
@@ -5927,7 +5953,39 @@
         }
     }
 
+    private final class AccountAccessTracker extends IAccountAccessTracker.Stub {
+        @Override
+        public void onAccountAccessed() throws RemoteException {
+            final int uid = Binder.getCallingUid();
+            if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
+                return;
+            }
+            final int userId = UserHandle.getCallingUserId();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                for (Account account : getAccounts(userId, mContext.getOpPackageName())) {
+                    IAccountAccessTracker accountTracker = account.getAccessTracker();
+                    if (accountTracker != null && asBinder() == accountTracker.asBinder()) {
+                        // An app just accessed the account. At this point it knows about
+                        // it and there is not need to hide this account from the app.
+                        if (!hasAccountAccess(account, null, uid)) {
+                            updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
+                                    uid, true);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
     private final class AccountManagerInternalImpl extends AccountManagerInternal {
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private AccountManagerBackupHelper mBackupHelper;
+
         @Override
         public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
                 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
@@ -5948,7 +6006,8 @@
                 return;
             }
 
-            if (hasAccountAccess(account, packageName, new UserHandle(userId))) {
+            if (AccountManagerService.this.hasAccountAccess(account, packageName,
+                    new UserHandle(userId))) {
                 Bundle result = new Bundle();
                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
                 callback.sendResult(result);
@@ -5964,7 +6023,44 @@
             }
 
             Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
-            doNotification(mUsers.get(userId), account, null, intent, packageName, userId);
+            final UserAccounts userAccounts;
+            synchronized (mUsers) {
+                userAccounts = mUsers.get(userId);
+            }
+            doNotification(userAccounts, account, null, intent, packageName, userId);
+        }
+
+        @Override
+        public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) {
+            // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
+            mAppPermissionChangeListeners.add(listener);
+        }
+
+        @Override
+        public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
+            return AccountManagerService.this.hasAccountAccess(account, null, uid);
+        }
+
+        @Override
+        public byte[] backupAccountAccessPermissions(int userId) {
+            synchronized (mLock) {
+                if (mBackupHelper == null) {
+                    mBackupHelper = new AccountManagerBackupHelper(
+                            AccountManagerService.this, this);
+                }
+                return mBackupHelper.backupAccountAccessPermissions(userId);
+            }
+        }
+
+        @Override
+        public void restoreAccountAccessPermissions(byte[] data, int userId) {
+            synchronized (mLock) {
+                if (mBackupHelper == null) {
+                    mBackupHelper = new AccountManagerBackupHelper(
+                            AccountManagerService.this, this);
+                }
+                mBackupHelper.restoreAccountAccessPermissions(data, userId);
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 6cdabaa..43eb251 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import android.annotation.NonNull;
-import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
@@ -25,7 +24,6 @@
 import android.os.FileUtils;
 import android.os.Process;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -82,7 +80,7 @@
     private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt";
     static final String IMAGE_EXTENSION = ".png";
 
-    @VisibleForTesting static final String TAG_TASK = "task";
+    private static final String TAG_TASK = "task";
 
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
@@ -409,43 +407,18 @@
         return null;
     }
 
-    @VisibleForTesting
     List<TaskRecord> restoreTasksForUserLocked(final int userId) {
         final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
         File userTasksDir = getUserTasksDir(userId);
+
         File[] recentFiles = userTasksDir.listFiles();
         if (recentFiles == null) {
             Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
             return tasks;
         }
 
-        // Get the last persist uptime so we know how to adjust the first/last active times for each
-        // task
-        ContentResolver cr = mService.mContext.getContentResolver();
-        long lastPersistUptime = Settings.Secure.getLong(cr,
-                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0);
-        if (DEBUG) {
-            Slog.d(TaskPersister.TAG, "restoreTasksForUserLocked: lastPersistUptime=" +
-                    lastPersistUptime);
-        }
-
-        // Adjust the overview last visible task active time as we adjust the task active times when
-        // loading. See TaskRecord.restoreFromXml().  If we have not migrated yet, SystemUI will
-        // migrate the old value into the system setting.
-        if (lastPersistUptime > 0) {
-            long overviewLastActiveTime = Settings.Secure.getLongForUser(cr,
-                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, 0, userId);
-            if (DEBUG) {
-                Slog.d(TaskPersister.TAG, "restoreTasksForUserLocked: overviewLastActiveTime=" +
-                        overviewLastActiveTime + " lastPersistUptime=" + lastPersistUptime);
-            }
-            Settings.Secure.putLongForUser(cr,
-                    Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME,
-                    -lastPersistUptime + overviewLastActiveTime, userId);
-        }
-
         for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
             File taskFile = recentFiles[taskNdx];
             if (DEBUG) {
@@ -466,11 +439,15 @@
                     if (event == XmlPullParser.START_TAG) {
                         if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name);
                         if (TAG_TASK.equals(name)) {
-                            final TaskRecord task = TaskRecord.restoreFromXml(in, mService,
-                                    mStackSupervisor, lastPersistUptime);
+                            final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);
                             if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: 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));
+
                                 final int taskId = task.taskId;
                                 if (mStackSupervisor.anyTaskForIdLocked(taskId,
                                         /* restoreFromRecents= */ false, 0) != null) {
@@ -486,12 +463,6 @@
                                     task.isPersistable = true;
                                     tasks.add(task);
                                     recoveredTaskIds.add(taskId);
-
-                                    // We've shifted the first and last active times, so we need to
-                                    // persist the new task data to disk otherwise they will not
-                                    // have the updated values.  This is only done once whenever
-                                    // the recents are first loaded for the user.
-                                    wakeup(task, false);
                                 }
                             } else {
                                 Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile="
@@ -780,15 +751,6 @@
                         }
                     }
                 }
-
-                // Always update the task persister uptime when updating any tasks
-                if (DEBUG) {
-                    Slog.d(TAG, "LazyTaskWriter: Updating last write uptime=" +
-                            SystemClock.elapsedRealtime());
-                }
-                Settings.Secure.putLong(mService.mContext.getContentResolver(),
-                        Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME,
-                        SystemClock.elapsedRealtime());
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index b3d8027..3f6db99 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -39,14 +39,12 @@
 import android.os.Debug;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.DisplayMetrics;
 import android.util.Slog;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
 
@@ -152,10 +150,8 @@
     ComponentName realActivity; // The actual activity component that started the task.
     boolean realActivitySuspended; // True if the actual activity component that started the
                                    // task is suspended.
-    long firstActiveTime;   // First time this task was active, relative to boot time. This can be
-                            // negative if this task was last used prior to boot.
-    long lastActiveTime;    // Last time this task was active, relative to boot time. This can be
-                            // negative if this task was last used prior to boot.
+    long firstActiveTime;   // First time this task was active.
+    long lastActiveTime;    // Last time this task was active, including sleep.
     boolean inRecents;      // Actually in the recents list?
     boolean isAvailable;    // Is the activity available to be launched?
     boolean rootWasReset;   // True if the intent at the root of the task had
@@ -381,14 +377,14 @@
     }
 
     void touchActiveTime() {
-        lastActiveTime = SystemClock.elapsedRealtime();
+        lastActiveTime = System.currentTimeMillis();
         if (firstActiveTime == 0) {
             firstActiveTime = lastActiveTime;
         }
     }
 
     long getInactiveDuration() {
-        return SystemClock.elapsedRealtime() - lastActiveTime;
+        return System.currentTimeMillis() - lastActiveTime;
     }
 
     /** Sets the original intent, and the calling uid and package. */
@@ -459,9 +455,8 @@
             rootWasReset = true;
         }
         userId = UserHandle.getUserId(info.applicationInfo.uid);
-        mUserSetupComplete = mService != null &&
-                Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
-                        USER_SETUP_COMPLETE, 0, userId) != 0;
+        mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
+                USER_SETUP_COMPLETE, 0, userId) != 0;
         if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
             // If the activity itself has requested auto-remove, then just always do it.
             autoRemoveRecents = true;
@@ -1173,9 +1168,7 @@
         if (lastTaskDescription != null) {
             lastTaskDescription.saveToXml(out);
         }
-        if (mLastThumbnailInfo != null) {
-            mLastThumbnailInfo.saveToXml(out);
-        }
+        mLastThumbnailInfo.saveToXml(out);
         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
         out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
@@ -1197,11 +1190,9 @@
             out.endTag(null, TAG_AFFINITYINTENT);
         }
 
-        if (intent != null) {
-            out.startTag(null, TAG_INTENT);
-            intent.saveToXml(out);
-            out.endTag(null, TAG_INTENT);
-        }
+        out.startTag(null, TAG_INTENT);
+        intent.saveToXml(out);
+        out.endTag(null, TAG_INTENT);
 
         final ArrayList<ActivityRecord> activities = mActivities;
         final int numActivities = activities.size();
@@ -1220,9 +1211,8 @@
         }
     }
 
-    static TaskRecord restoreFromXml(XmlPullParser in, ActivityManagerService service,
-            ActivityStackSupervisor stackSupervisor, long lastPersistUptime)
-                    throws IOException, XmlPullParserException {
+    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+            throws IOException, XmlPullParserException {
         Intent intent = null;
         Intent affinityIntent = null;
         ArrayList<ActivityRecord> activities = new ArrayList<>();
@@ -1335,31 +1325,6 @@
             }
         }
 
-        if (lastPersistUptime > 0) {
-            if (TaskPersister.DEBUG) {
-                Slog.d(TaskPersister.TAG, "TaskRecord: Adjust firstActiveTime=" + firstActiveTime +
-                        " lastPersistUptime=" + lastPersistUptime);
-                Slog.d(TaskPersister.TAG, "TaskRecord: Migrate lastActiveTime=" + lastActiveTime +
-                        " lastActiveTime=" + lastPersistUptime);
-            }
-            // The first and last task active times are relative to the last boot time, so offset
-            // them to be prior to the current boot time
-            firstActiveTime = -lastPersistUptime + firstActiveTime;
-            lastActiveTime = -lastPersistUptime + lastActiveTime;
-        } else {
-            // The first/last active times are still absolute clock times, so offset them to be
-            // relative to the current boot time
-            long currentTime = System.currentTimeMillis();
-            if (TaskPersister.DEBUG) {
-                Slog.d(TaskPersister.TAG, "TaskRecord: Migrate firstActiveTime=" + firstActiveTime +
-                                " currentTime=" + currentTime);
-                Slog.d(TaskPersister.TAG, "TaskRecord: Migrate lastActiveTime=" + lastActiveTime +
-                                " currentTime=" + currentTime);
-            }
-            firstActiveTime = -Math.max(0, currentTime - firstActiveTime);
-            lastActiveTime = -Math.max(0, currentTime - lastActiveTime);
-        }
-
         int event;
         while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
                 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
@@ -1409,7 +1374,7 @@
                     + ": effectiveUid=" + effectiveUid);
         }
 
-        final TaskRecord task = new TaskRecord(service, taskId, intent,
+        final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
                 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
@@ -1812,7 +1777,7 @@
         pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
                 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
                 pw.print(" isResizeable=" + isResizeable());
-                pw.print(" firstActiveTime=" + firstActiveTime);
+                pw.print(" firstActiveTime=" + lastActiveTime);
                 pw.print(" lastActiveTime=" + lastActiveTime);
                 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
     }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 12955f5..4e236d1 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -482,7 +482,7 @@
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
                 syncManager.scheduleSync(account, userId, uId, authority, extras,
-                        false /* onlyThoseWithUnkownSyncableState */);
+                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -548,7 +548,7 @@
             } else {
                 syncManager.scheduleSync(
                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
-                        false /* onlyThoseWithUnknownSyncableState */);
+                        SyncStorageEngine.AuthorityInfo.UNDEFINED);
             }
         } finally {
             restoreCallingIdentity(identityToken);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 705eae6..8c71478 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -504,7 +504,7 @@
             @Override
             public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
                 scheduleSync(info.account, info.userId, reason, info.provider, extras,
-                        false);
+                        AuthorityInfo.UNDEFINED);
             }
         });
 
@@ -534,7 +534,7 @@
                 if (!removed) {
                     scheduleSync(null, UserHandle.USER_ALL,
                             SyncOperation.REASON_SERVICE_CHANGED,
-                            type.authority, null, false /* onlyThoseWithUnkownSyncableState */);
+                            type.authority, null, AuthorityInfo.UNDEFINED);
                 }
             }
         }, mSyncHandler);
@@ -576,6 +576,15 @@
         mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
         mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
 
+        mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
+            // If the UID gained access to the account kick-off syncs lacking account access
+            if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
+                scheduleSync(account, UserHandle.getUserId(uid),
+                        SyncOperation.REASON_ACCOUNTS_UPDATED,
+                        null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS);
+            }
+        });
+
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                 BatteryStats.SERVICE_NAME));
 
@@ -671,7 +680,7 @@
                         service.type.accountType, userHandle)) {
                     if (!canAccessAccount(account, packageName, userId)) {
                         mAccountManager.updateAppPermission(account,
-                                AccountManager.ACCOUNT_ACCESS_TOKEN, service.uid, true);
+                                AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
                     }
                 }
             }
@@ -778,10 +787,11 @@
      * @param extras a Map of SyncAdapter-specific information to control
      *          syncs of a specific provider. Can be null. Is ignored
      *          if the url is null.
-     * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
+     * @param targetSyncState Only sync authorities that have the specified sync state.
+     *           Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
-            String requestedAuthority, Bundle extras, boolean onlyThoseWithUnkownSyncableState) {
+            String requestedAuthority, Bundle extras, int targetSyncState) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -888,7 +898,7 @@
                                 if (result != null
                                         && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
                                     scheduleSync(account.account, userId, reason, authority,
-                                            finalExtras, onlyThoseWithUnkownSyncableState);
+                                            finalExtras, targetSyncState);
                                 }
                             }
                         ));
@@ -903,9 +913,10 @@
                     isSyncable = AuthorityInfo.SYNCABLE;
                 }
 
-                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
+                if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
                     continue;
                 }
+
                 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
                     continue;
                 }
@@ -931,7 +942,7 @@
 
                 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
 
-                if (isSyncable < 0) {
+                if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
                     // Initialisation sync.
                     Bundle newExtras = new Bundle();
                     newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
@@ -950,8 +961,8 @@
                                     owningUid, owningPackage, reason, source,
                                     authority, newExtras, allowParallelSyncs)
                     );
-                }
-                if (!onlyThoseWithUnkownSyncableState) {
+                } else if (targetSyncState == AuthorityInfo.UNDEFINED
+                        || targetSyncState == isSyncable) {
                     if (isLoggable) {
                         Slog.v(TAG, "scheduleSync:"
                                 + " delay until " + delayUntil
@@ -1076,7 +1087,7 @@
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
         scheduleSync(account, userId, reason, authority, extras,
-                false /* onlyThoseWithUnkownSyncableState */);
+                AuthorityInfo.UNDEFINED);
     }
 
     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1535,7 +1546,7 @@
                 mContext.getOpPackageName());
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
-                    true /* onlyThoseWithUnknownSyncableState */);
+                    AuthorityInfo.NOT_INITIALIZED);
         }
     }
 
@@ -2714,7 +2725,8 @@
 
             if (syncTargets != null) {
                 scheduleSync(syncTargets.account, syncTargets.userId,
-                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, true);
+                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
+                null, AuthorityInfo.NOT_INITIALIZED);
             }
         }
 
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8289bae..069ae73 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -211,6 +211,12 @@
 
     public static class AuthorityInfo {
         // Legal values of getIsSyncable
+
+        /**
+         * The syncable state is undefined.
+         */
+        public static final int UNDEFINED = -2;
+
         /**
          * Default state for a newly installed adapter. An uninitialized adapter will receive an
          * initialization sync which are governed by a different set of rules to that of regular
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 7626e2a..53dbed2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -90,6 +90,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -290,6 +291,7 @@
     private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
     private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
     private static final int MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED = 12;
+    private static final int MSG_SET_FIREWALL_RULES = 13;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
@@ -715,6 +717,7 @@
             synchronized (mUidRulesFirstLock) {
                 updatePowerSaveWhitelistUL();
                 updateRulesForRestrictPowerUL();
+                updateRulesForAppIdleUL();
             }
         }
     };
@@ -2214,23 +2217,23 @@
     @Override
     public void setDeviceIdleMode(boolean enabled) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDeviceIdleMode");
         try {
             synchronized (mUidRulesFirstLock) {
-                if (mDeviceIdleMode != enabled) {
-                    mDeviceIdleMode = enabled;
-                    if (mSystemReady) {
-                        // Device idle change means we need to rebuild rules for all
-                        // known apps, so do a global refresh.
-                        updateRulesForRestrictPowerUL();
-                    }
-                    if (enabled) {
-                        EventLogTags.writeDeviceIdleOnPhase("net");
-                    } else {
-                        EventLogTags.writeDeviceIdleOffPhase("net");
-                    }
+                if (mDeviceIdleMode == enabled) {
+                    return;
                 }
+                mDeviceIdleMode = enabled;
+                if (mSystemReady) {
+                    // Device idle change means we need to rebuild rules for all
+                    // known apps, so do a global refresh.
+                    updateRulesForRestrictPowerUL();
+                }
+            }
+            if (enabled) {
+                EventLogTags.writeDeviceIdleOnPhase("net");
+            } else {
+                EventLogTags.writeDeviceIdleOffPhase("net");
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -2654,10 +2657,10 @@
                     uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
                 }
             }
-            setUidFirewallRules(chain, uidRules);
+            setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE);
+        } else {
+            setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE);
         }
-
-        enableFirewallChainUL(chain, enabled);
     }
 
     private boolean isWhitelistedBatterySaverUL(int uid) {
@@ -2701,7 +2704,7 @@
                 }
             }
 
-            setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
+            setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
@@ -2731,6 +2734,7 @@
     private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForGlobalChangeAL");
         try {
+            updateRulesForAppIdleUL();
             updateRulesForRestrictPowerUL();
             updateRulesForRestrictBackgroundUL();
 
@@ -2744,11 +2748,11 @@
         }
     }
 
+    // TODO: rename / document to make it clear these are global (not app-specific) rules
     private void updateRulesForRestrictPowerUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
         try {
             updateRulesForDeviceIdleUL();
-            updateRulesForAppIdleUL();
             updateRulesForPowerSaveUL();
             updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
         } finally {
@@ -3356,6 +3360,18 @@
                     removeInterfaceQuota((String) msg.obj);
                     return true;
                 }
+                case MSG_SET_FIREWALL_RULES: {
+                    final int chain = msg.arg1;
+                    final int toggle = msg.arg2;
+                    final SparseIntArray uidRules = (SparseIntArray) msg.obj;
+                    if (uidRules != null) {
+                        setUidFirewallRules(chain, uidRules);
+                    }
+                    if (toggle != CHAIN_TOGGLE_NONE) {
+                        enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
+                    }
+                    return true;
+                }
                 default: {
                     return false;
                 }
@@ -3405,6 +3421,31 @@
         }
     }
 
+    private static final int CHAIN_TOGGLE_NONE = 0;
+    private static final int CHAIN_TOGGLE_ENABLE = 1;
+    private static final int CHAIN_TOGGLE_DISABLE = 2;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            CHAIN_TOGGLE_NONE,
+            CHAIN_TOGGLE_ENABLE,
+            CHAIN_TOGGLE_DISABLE
+    })
+    public @interface ChainToggleType {
+    }
+
+    /**
+     * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
+     * {@link #enableFirewallChainUL(int, boolean)} asynchronously.
+     *
+     * @param chain firewall chain.
+     * @param uidRules new UID rules; if {@code null}, only toggles chain state.
+     * @param toggle whether the chain should be enabled, disabled, or not changed.
+     */
+    private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules,
+            @ChainToggleType int toggle) {
+        mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget();
+    }
+
     /**
      * Set uid rules on a particular firewall chain. This is going to synchronize the rules given
      * here to netd.  It will clean up dead rules and make sure the target chain only contains rules
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 8d926f5..68b465a 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -60,7 +60,7 @@
 
     public EphemeralResolverConnection(Context context, ComponentName componentName) {
         mContext = context;
-        mIntent = new Intent().setComponent(componentName);
+        mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName);
     }
 
     public final List<EphemeralResolveInfo> getEphemeralResolveInfoList(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 419e4ad..d3207cd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -212,6 +212,7 @@
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.MathUtils;
+import android.util.Pair;
 import android.util.PrintStreamPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -1128,6 +1129,7 @@
     final @NonNull String mRequiredInstallerPackage;
     final @NonNull String mRequiredUninstallerPackage;
     final @Nullable String mSetupWizardPackage;
+    final @Nullable String mStorageManagerPackage;
     final @NonNull String mServicesSystemSharedLibraryPackageName;
     final @NonNull String mSharedSystemSharedLibraryPackageName;
 
@@ -2469,6 +2471,9 @@
             }
             mExpectingBetter.clear();
 
+            // Resolve the storage manager.
+            mStorageManagerPackage = getStorageManagerPackageName();
+
             // Resolve protected action filters. Only the setup wizard is allowed to
             // have a high priority filter for these actions.
             mSetupWizardPackage = getSetupWizardPackageName();
@@ -11261,6 +11266,19 @@
 
     private static final class EphemeralIntentResolver
             extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
+        /**
+         * The result that has the highest defined order. Ordering applies on a
+         * per-package basis. Mapping is from package name to Pair of order and
+         * EphemeralResolveInfo.
+         * <p>
+         * NOTE: This is implemented as a field variable for convenience and efficiency.
+         * By having a field variable, we're able to track filter ordering as soon as
+         * a non-zero order is defined. Otherwise, multiple loops across the result set
+         * would be needed to apply ordering. If the intent resolver becomes re-entrant,
+         * this needs to be contained entirely within {@link #filterResults()}.
+         */
+        final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
+
         @Override
         protected EphemeralResolveIntentInfo[] newArray(int size) {
             return new EphemeralResolveIntentInfo[size];
@@ -11277,7 +11295,51 @@
             if (!sUserManager.exists(userId)) {
                 return null;
             }
-            return info.getEphemeralResolveInfo();
+            final String packageName = info.getEphemeralResolveInfo().getPackageName();
+            final Integer order = info.getOrder();
+            final Pair<Integer, EphemeralResolveInfo> lastOrderResult =
+                    mOrderResult.get(packageName);
+            // ordering is enabled and this item's order isn't high enough
+            if (lastOrderResult != null && lastOrderResult.first >= order) {
+                return null;
+            }
+            final EphemeralResolveInfo res = info.getEphemeralResolveInfo();
+            if (order > 0) {
+                // non-zero order, enable ordering
+                mOrderResult.put(packageName, new Pair<>(order, res));
+            }
+            return res;
+        }
+
+        @Override
+        protected void filterResults(List<EphemeralResolveInfo> results) {
+            // only do work if ordering is enabled [most of the time it won't be]
+            if (mOrderResult.size() == 0) {
+                return;
+            }
+            int resultSize = results.size();
+            for (int i = 0; i < resultSize; i++) {
+                final EphemeralResolveInfo info = results.get(i);
+                final String packageName = info.getPackageName();
+                final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
+                if (savedInfo == null) {
+                    // package doesn't having ordering
+                    continue;
+                }
+                if (savedInfo.second == info) {
+                    // circled back to the highest ordered item; remove from order list
+                    mOrderResult.remove(savedInfo);
+                    if (mOrderResult.size() == 0) {
+                        // no more ordered items
+                        break;
+                    }
+                    continue;
+                }
+                // item has a worse order, remove it from the result list
+                results.remove(i);
+                resultSize--;
+                i--;
+            }
         }
     }
 
@@ -15513,6 +15575,12 @@
                 callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) {
             return true;
         }
+
+        // Allow storage manager to silently uninstall.
+        if (mStorageManagerPackage != null &&
+                callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
+            return true;
+        }
         return false;
     }
 
@@ -17728,6 +17796,22 @@
         }
     }
 
+    private @Nullable String getStorageManagerPackageName() {
+        final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
+
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
+                        | MATCH_DISABLED_COMPONENTS,
+                UserHandle.myUserId());
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            Slog.e(TAG, "There should probably be exactly one storage manager; found "
+                    + matches.size() + ": matches=" + matches);
+            return null;
+        }
+    }
+
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2824e6e..570b93c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2538,18 +2538,18 @@
 
     boolean setDeviceIdleModeInternal(boolean enabled) {
         synchronized (mLock) {
-            if (mDeviceIdleMode != enabled) {
-                mDeviceIdleMode = enabled;
-                updateWakeLockDisabledStatesLocked();
-                if (enabled) {
-                    EventLogTags.writeDeviceIdleOnPhase("power");
-                } else {
-                    EventLogTags.writeDeviceIdleOffPhase("power");
-                }
-                return true;
+            if (mDeviceIdleMode == enabled) {
+                return false;
             }
-            return false;
+            mDeviceIdleMode = enabled;
+            updateWakeLockDisabledStatesLocked();
         }
+        if (enabled) {
+            EventLogTags.writeDeviceIdleOnPhase("power");
+        } else {
+            EventLogTags.writeDeviceIdleOffPhase("power");
+        }
+        return true;
     }
 
     boolean setLightDeviceIdleModeInternal(boolean enabled) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 022848e..1ee5a22 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -121,6 +121,9 @@
 
     private final AppTokenList mTmpExitingAppTokens = new AppTokenList();
 
+    /** The window that was previously hiding the Keyguard. */
+    private WindowState mLastShowWinWhenLocked;
+
     private String forceHidingToString() {
         switch (mForceHiding) {
             case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
@@ -221,27 +224,43 @@
         }
     }
 
+    /**
+     * @return The window that is currently hiding the Keyguard, or if it was hiding the Keyguard,
+     *         and it's still animating.
+     */
+    private WindowState getWinShowWhenLockedOrAnimating() {
+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        if (winShowWhenLocked != null) {
+            return winShowWhenLocked;
+        }
+        if (mLastShowWinWhenLocked != null && mLastShowWinWhenLocked.isOnScreen()
+                && mLastShowWinWhenLocked.isAnimatingLw()
+                && (mLastShowWinWhenLocked.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+            return mLastShowWinWhenLocked;
+        }
+        return null;
+    }
+
     private boolean shouldForceHide(WindowState win) {
         final WindowState imeTarget = mService.mInputMethodTarget;
         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
                 ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
                         || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs));
 
-        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        final WindowState winShowWhenLocked = getWinShowWhenLockedOrAnimating();
         final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
                 null : winShowWhenLocked.mAppToken;
 
         boolean allowWhenLocked = false;
         // Show IME over the keyguard if the target allows it
         allowWhenLocked |= (win.mIsImWindow || imeTarget == win) && showImeOverKeyguard;
-        // Show SHOW_WHEN_LOCKED windows
-        allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
-        // Show windows that are attached to SHOW_WHEN_LOCKED windows
-        allowWhenLocked |= win.mAttachedWindow != null
-                && (win.mAttachedWindow.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+        // Show SHOW_WHEN_LOCKED windows that turn on the screen
+        allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.mTurnOnScreen;
 
         if (appShowWhenLocked != null) {
             allowWhenLocked |= appShowWhenLocked == win.mAppToken
+                    // Show all SHOW_WHEN_LOCKED windows if some apps are shown over lockscreen
+                    || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
                     // Show error dialogs over apps that are shown on lockscreen
                     || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
         }
@@ -556,6 +575,11 @@
                 mPostKeyguardExitAnimation = null;
             }
         }
+
+        final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+        if (winShowWhenLocked != null) {
+            mLastShowWinWhenLocked = winShowWhenLocked;
+        }
     }
 
     private void updateWallpaperLocked(int displayId) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4372dea..707b137 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
@@ -9192,7 +9193,7 @@
     }
 
     @Override
-    public void setForcedDisplayDensity(int displayId, int density) {
+    public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
                 PackageManager.PERMISSION_GRANTED) {
@@ -9202,16 +9203,20 @@
         if (displayId != Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("Can only set the default display");
         }
+
+        final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser",
+                null);
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
                 final DisplayContent displayContent = getDisplayContentLocked(displayId);
-                if (displayContent != null) {
+                if (displayContent != null && mCurrentUserId == targetUserId) {
                     setForcedDisplayDensityLocked(displayContent, density);
-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                            Settings.Secure.DISPLAY_DENSITY_FORCED,
-                            Integer.toString(density), mCurrentUserId);
                 }
+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                        Settings.Secure.DISPLAY_DENSITY_FORCED,
+                        Integer.toString(density), targetUserId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -9219,7 +9224,7 @@
     }
 
     @Override
-    public void clearForcedDisplayDensity(int displayId) {
+    public void clearForcedDisplayDensityForUser(int displayId, int userId) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
                 PackageManager.PERMISSION_GRANTED) {
@@ -9229,16 +9234,20 @@
         if (displayId != Display.DEFAULT_DISPLAY) {
             throw new IllegalArgumentException("Can only set the default display");
         }
+
+        final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser",
+                null);
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
                 final DisplayContent displayContent = getDisplayContentLocked(displayId);
-                if (displayContent != null) {
+                if (displayContent != null && mCurrentUserId == callingUserId) {
                     setForcedDisplayDensityLocked(displayContent,
                             displayContent.mInitialDisplayDensity);
-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                            Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId);
                 }
+                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                        Settings.Secure.DISPLAY_DENSITY_FORCED, "", callingUserId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 00f4a45..0285f70 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -228,8 +228,6 @@
     int mAttrType;
 
     static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
-    long mDeferTransactionUntilFrame = -1;
-    long mDeferTransactionTime = -1;
 
     boolean mForceScaleUntilResize;
 
@@ -2055,35 +2053,11 @@
         if (!mWin.isChildWindow()) {
             return;
         }
-        mDeferTransactionUntilFrame = frameNumber;
-        mDeferTransactionTime = System.currentTimeMillis();
         mSurfaceController.deferTransactionUntil(
                 mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
                 frameNumber);
     }
 
-    // Defer the current transaction to the frame number of the last saved transaction.
-    // We do this to avoid shooting through an unsynchronized transaction while something is
-    // pending. This is generally fine, as either we will get in on the synchronization,
-    // or SurfaceFlinger will see that the frame has already occured. The only
-    // potential problem is in frame number resets so we reset things with a timeout
-    // every so often to be careful.
-    void deferToPendingTransaction() {
-        if (mDeferTransactionUntilFrame < 0) {
-            return;
-        }
-        long time = System.currentTimeMillis();
-        if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) {
-            mDeferTransactionTime = -1;
-            mDeferTransactionUntilFrame = -1;
-        } else if (mWin.mAttachedWindow != null &&
-                mWin.mAttachedWindow.mWinAnimator.hasSurface()) {
-            mSurfaceController.deferTransactionUntil(
-                    mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
-                    mDeferTransactionUntilFrame);
-        }
-    }
-
     /**
      * Sometimes we need to synchronize the first frame of animation with some external event.
      * To achieve this, we prolong the start of the animation and keep producing the first frame of
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index fa5e3ca..5a79da9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -742,10 +742,6 @@
 
                 // Moved from updateWindowsAndWallpaperLocked().
                 if (w.mHasSurface) {
-                    // If we have recently synchronized a previous transaction for this
-                    // window ensure we don't push through an unsynchronized one now.
-                    winAnimator.deferToPendingTransaction();
-
                     // Take care of the window being ready to display.
                     final boolean committed = winAnimator.commitFinishDrawingLocked();
                     if (isDefaultDisplay && committed) {
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
index 7571f79..984a484 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -16,36 +16,19 @@
 
 package com.android.server.am;
 
-import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.pm.ActivityInfo;
 import android.content.pm.UserInfo;
 import android.os.Environment;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.util.SparseBooleanArray;
-import android.util.Xml;
 
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
 import com.android.server.am.TaskPersister;
 
 import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
 import java.util.Random;
 
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 public class TaskPersisterTest extends AndroidTestCase {
     private static final String TEST_USER_NAME = "AM-Test-User";
 
@@ -86,140 +69,6 @@
                 taskIdsOnFile.equals(newTaskIdsOnFile));
     }
 
-    public void testActiveTimeMigration() {
-        // Simulate a migration scenario by setting the last write uptime to zero
-        ContentResolver cr = getContext().getContentResolver();
-        Settings.Secure.putLong(cr,
-                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0);
-
-        // Create a dummy task record with an absolute time 1s before now
-        long pastOffset = 1000;
-        long activeTime = System.currentTimeMillis() - pastOffset;
-        TaskRecord tr0 = createDummyTaskRecordWithActiveTime(activeTime, activeTime);
-
-        // Save and load the tasks with no last persist uptime (0)
-        String tr0XmlStr = serializeTaskRecordToXmlString(tr0);
-        TaskRecord xtr0 = unserializeTaskRecordFromXmlString(tr0XmlStr, 0);
-
-        // Ensure that the absolute time has been migrated to be relative to the current elapsed
-        // time
-        assertTrue("Expected firstActiveTime to be migrated from: " + tr0.firstActiveTime +
-                " instead found: " + xtr0.firstActiveTime,
-                        xtr0.firstActiveTime <= -pastOffset);
-        assertTrue("Expected lastActiveTime to be migrated from: " + tr0.lastActiveTime +
-                " instead found: " + xtr0.lastActiveTime,
-                        xtr0.lastActiveTime <= -pastOffset);
-
-        // Ensure that the last active uptime is not set so that SystemUI can migrate it itself
-        // assuming that the last persist time is zero
-        Settings.Secure.putLongForUser(cr,
-                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, 0, testUserId);
-        mTaskPersister.restoreTasksForUserLocked(testUserId);
-        long lastVisTaskActiveTime = Settings.Secure.getLongForUser(cr,
-                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, -1, testUserId);
-        assertTrue("Expected last visible task active time is zero", lastVisTaskActiveTime == 0);
-    }
-
-    public void testActiveTimeOffsets() {
-        // Simulate a normal boot scenario by setting the last write uptime
-        long lastWritePastOffset = 1000;
-        long lastVisActivePastOffset = 500;
-        ContentResolver cr = getContext().getContentResolver();
-        Settings.Secure.putLong(cr,
-                Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, lastWritePastOffset);
-
-        // Create a dummy task record with an absolute time 1s before now
-        long activeTime = 250;
-        TaskRecord tr0 = createDummyTaskRecordWithActiveTime(activeTime, activeTime);
-
-        // Save and load the tasks with the last persist time
-        String tr0XmlStr = serializeTaskRecordToXmlString(tr0);
-        TaskRecord xtr0 = unserializeTaskRecordFromXmlString(tr0XmlStr, lastWritePastOffset);
-
-        // Ensure that the prior elapsed time has been offset to be relative to the current boot
-        // time
-        assertTrue("Expected firstActiveTime to be offset from: " + tr0.firstActiveTime +
-                " instead found: " + xtr0.firstActiveTime,
-                        xtr0.firstActiveTime <= (-lastWritePastOffset + activeTime));
-        assertTrue("Expected lastActiveTime to be offset from: " + tr0.lastActiveTime +
-                " instead found: " + xtr0.lastActiveTime,
-                        xtr0.lastActiveTime <= (-lastWritePastOffset + activeTime));
-
-        // Ensure that we update the last active uptime as well by simulating a restoreTasks call
-        Settings.Secure.putLongForUser(cr,
-                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, lastVisActivePastOffset,
-                        testUserId);
-        mTaskPersister.restoreTasksForUserLocked(testUserId);
-        long lastVisTaskActiveTime = Settings.Secure.getLongForUser(cr,
-                Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, Long.MAX_VALUE,
-                        testUserId);
-        assertTrue("Expected last visible task active time to be offset", lastVisTaskActiveTime <=
-                (-lastWritePastOffset + lastVisActivePastOffset));
-    }
-
-    private TaskRecord createDummyTaskRecordWithActiveTime(long firstActiveTime,
-            long lastActiveTime) {
-        ActivityInfo info = createDummyActivityInfo();
-        ActivityManager.TaskDescription td = new ActivityManager.TaskDescription();
-        TaskRecord t = new TaskRecord(null, 0, info, null, td, null);
-        t.firstActiveTime = firstActiveTime;
-        t.lastActiveTime = lastActiveTime;
-        return t;
-    }
-
-    private ActivityInfo createDummyActivityInfo() {
-        ActivityInfo info = new ActivityInfo();
-        info.applicationInfo = getContext().getApplicationInfo();
-        return info;
-    }
-
-    private String serializeTaskRecordToXmlString(TaskRecord tr) {
-        StringWriter stringWriter = new StringWriter();
-
-        try {
-            final XmlSerializer xmlSerializer = new FastXmlSerializer();
-            xmlSerializer.setOutput(stringWriter);
-
-            xmlSerializer.startDocument(null, true);
-            xmlSerializer.startTag(null, TaskPersister.TAG_TASK);
-            tr.saveToXml(xmlSerializer);
-            xmlSerializer.endTag(null, TaskPersister.TAG_TASK);
-            xmlSerializer.endDocument();
-            xmlSerializer.flush();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-
-        return stringWriter.toString();
-    }
-
-    private TaskRecord unserializeTaskRecordFromXmlString(String xmlStr, long lastPersistUptime) {
-        StringReader reader = null;
-        TaskRecord task = null;
-        try {
-            reader = new StringReader(xmlStr);
-            final XmlPullParser in = Xml.newPullParser();
-            in.setInput(reader);
-
-            int event;
-            while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
-                    event != XmlPullParser.END_TAG) {
-                final String name = in.getName();
-                if (event == XmlPullParser.START_TAG) {
-                    if (TaskPersister.TAG_TASK.equals(name)) {
-                        task = TaskRecord.restoreFromXml(in, null, null, lastPersistUptime);
-                    }
-                }
-                XmlUtils.skipCurrentTag(in);
-            }
-        } catch (Exception e) {
-            return null;
-        } finally {
-            IoUtils.closeQuietly(reader);
-        }
-        return task;
-    }
-
     private int createUser(String name, int flags) {
         UserInfo user = mUserManager.createUser(name, flags);
         if (user == null) {
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 03d6d21..7350eec 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -24,6 +24,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.location.CountryDetector;
 import android.net.Uri;
@@ -3021,4 +3022,79 @@
         return SubscriptionManager.getDefaultVoiceSubscriptionId();
     }
     //==== End of utility methods used only in compareStrictly() =====
+
+
+    /*
+     * The config held calling number conversion map, expected to convert to emergency number.
+     */
+    private static final String[] CONVERT_TO_EMERGENCY_MAP = Resources.getSystem().getStringArray(
+            com.android.internal.R.array.config_convert_to_emergency_number_map);
+    /**
+     * Check whether conversion to emergency number is enabled
+     *
+     * @return {@code true} when conversion to emergency numbers is enabled,
+     *         {@code false} otherwise
+     *
+     * @hide
+     */
+    public static boolean isConvertToEmergencyNumberEnabled() {
+        return CONVERT_TO_EMERGENCY_MAP != null && CONVERT_TO_EMERGENCY_MAP.length > 0;
+    }
+
+    /**
+     * Converts to emergency number based on the conversion map.
+     * The conversion map is declared as config_convert_to_emergency_number_map.
+     *
+     * Make sure {@link #isConvertToEmergencyNumberEnabled} is true before calling
+     * this function.
+     *
+     * @return The converted emergency number if the number matches conversion map,
+     * otherwise original number.
+     *
+     * @hide
+     */
+    public static String convertToEmergencyNumber(String number) {
+        if (TextUtils.isEmpty(number)) {
+            return number;
+        }
+
+        String normalizedNumber = normalizeNumber(number);
+
+        // The number is already emergency number. Skip conversion.
+        if (isEmergencyNumber(normalizedNumber)) {
+            return number;
+        }
+
+        for (String convertMap : CONVERT_TO_EMERGENCY_MAP) {
+            if (DBG) log("convertToEmergencyNumber: " + convertMap);
+            String[] entry = null;
+            String[] filterNumbers = null;
+            String convertedNumber = null;
+            if (!TextUtils.isEmpty(convertMap)) {
+                entry = convertMap.split(":");
+            }
+            if (entry != null && entry.length == 2) {
+                convertedNumber = entry[1];
+                if (!TextUtils.isEmpty(entry[0])) {
+                    filterNumbers = entry[0].split(",");
+                }
+            }
+            // Skip if the format of entry is invalid
+            if (TextUtils.isEmpty(convertedNumber) || filterNumbers == null
+                    || filterNumbers.length == 0) {
+                continue;
+            }
+
+            for (String filterNumber : filterNumbers) {
+                if (DBG) log("convertToEmergencyNumber: filterNumber = " + filterNumber
+                        + ", convertedNumber = " + convertedNumber);
+                if (!TextUtils.isEmpty(filterNumber) && filterNumber.equals(normalizedNumber)) {
+                    if (DBG) log("convertToEmergencyNumber: Matched. Successfully converted to: "
+                            + convertedNumber);
+                    return convertedNumber;
+                }
+            }
+        }
+        return number;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 58df301..76522f9 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -96,7 +96,7 @@
     }
 
     @Override
-    public void clearForcedDisplayDensity(int displayId) throws RemoteException {
+    public void clearForcedDisplayDensityForUser(int displayId, int userId) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -397,7 +397,8 @@
     }
 
     @Override
-    public void setForcedDisplayDensity(int displayId, int density) throws RemoteException {
+    public void setForcedDisplayDensityForUser(int displayId, int density, int userId)
+            throws RemoteException {
         // TODO Auto-generated method stub
     }