Merge changes Iccb6d089,I9c50a59f into nyc-dr1-dev
am: aa8263d85d

Change-Id: I366a23a1040fc88ecbb4cd7206cb95e992bb1fc7
diff --git a/api/test-current.txt b/api/test-current.txt
index 3b5c223..74e65d9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3255,6 +3255,7 @@
     method public java.lang.Object getAnimatedValue(java.lang.String);
     method public long getCurrentPlayTime();
     method public long getDuration();
+    method public static float getDurationScale();
     method public static long getFrameDelay();
     method public int getRepeatCount();
     method public int getRepeatMode();
@@ -3272,6 +3273,7 @@
     method public void setCurrentFraction(float);
     method public void setCurrentPlayTime(long);
     method public android.animation.ValueAnimator setDuration(long);
+    method public static void setDurationScale(float);
     method public void setEvaluator(android.animation.TypeEvaluator);
     method public void setFloatValues(float...);
     method public static void setFrameDelay(long);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 7465ed9..ed08a70 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.GET_ACCOUNTS;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
@@ -28,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.res.Resources;
 import android.database.SQLException;
 import android.os.Build;
@@ -265,6 +267,15 @@
             "android.accounts.AccountAuthenticator";
     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.
+     *
+     * @hide
+     */
+    public static final String ACCOUNT_ACCESS_TOKEN =
+            "com.android.abbfd278-af8b-415d-af8b-7571d5dab133";
+
     private final Context mContext;
     private final IAccountManager mService;
     private final Handler mMainHandler;
@@ -2960,4 +2971,49 @@
             }
         }.start();
     }
+
+    /**
+     * Gets whether a given package under a user has access to an account.
+     * Can be called only from the system UID.
+     *
+     * @param account The account for which to check.
+     * @param packageName The package for which to check.
+     * @param userHandle The user for which to check.
+     * @return True if the package can access the account.
+     *
+     * @hide
+     */
+    public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
+            @NonNull UserHandle userHandle) {
+        try {
+            return mService.hasAccountAccess(account, packageName, userHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates an intent to request access to a given account for a UID.
+     * The returned intent should be stated for a result where {@link
+     * Activity#RESULT_OK} result means access was granted whereas {@link
+     * Activity#RESULT_CANCELED} result means access wasn't granted. Can
+     * be called only from the system UID.
+     *
+     * @param account The account for which to request.
+     * @param packageName The package name which to request.
+     * @param userHandle The user for which to request.
+     * @return The intent to request account access or null if the package
+     *     doesn't exist.
+     *
+     * @hide
+     */
+    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
+            @NonNull String packageName, @NonNull UserHandle userHandle) {
+        try {
+            return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
+                    userHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
new file mode 100644
index 0000000..d777643
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerInternal.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.RemoteCallback;
+
+/**
+ * Account manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AccountManagerInternal {
+
+    /**
+     * 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
+     * {@link AccountManager#KEY_BOOLEAN_RESULT} key.
+     *
+     * @param account The account for which to request.
+     * @param packageName The package name for which to request.
+     * @param userId Concrete user id for which to request.
+     * @param callback A callback for receiving the result.
+     */
+    public abstract void requestAccountAccess(@NonNull  Account account,
+            @NonNull String packageName, @IntRange(from = 0) int userId,
+            @NonNull RemoteCallback callback);
+}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 12b2b9c..8d0ce58 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -35,12 +35,10 @@
  */
 public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
     public static final String EXTRAS_ACCOUNT = "account";
-    public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
     public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
     public static final String EXTRAS_RESPONSE = "response";
-    public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
-    public static final String EXTRAS_PACKAGES = "application";
     public static final String EXTRAS_REQUESTING_UID = "uid";
+
     private Account mAccount;
     private String mAuthTokenType;
     private int mUid;
@@ -109,7 +107,11 @@
                 }
             }
         };
-        AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
+
+        if (!AccountManager.ACCOUNT_ACCESS_TOKEN.equals(mAuthTokenType)) {
+            AccountManager.get(this).getAuthTokenLabel(mAccount.type,
+                    mAuthTokenType, callback, null);
+        }
 
         findViewById(R.id.allow_button).setOnClickListener(this);
         findViewById(R.id.deny_button).setOnClickListener(this);
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 7199288..56a6488 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -19,8 +19,10 @@
 import android.accounts.IAccountManagerResponse;
 import android.accounts.Account;
 import android.accounts.AuthenticatorDescription;
+import android.content.IntentSender;
 import android.os.Bundle;
-
+import android.os.RemoteCallback;
+import android.os.UserHandle;
 
 /**
  * Central application service that provides account management.
@@ -102,4 +104,10 @@
     /* Check if credentials update is suggested */
     void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
         String statusToken);
+
+    /* Check if the package in a user can access an account */
+    boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
+    /* Crate an intent to request account access for package and a given user id */
+    IntentSender createRequestAccountAccessIntentSenderAsUser(in Account account,
+        String packageName, in UserHandle userHandle);
 }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e3f8fa4..7e16e3e 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -261,6 +262,7 @@
     /**
      * @hide
      */
+    @TestApi
     public static void setDurationScale(float durationScale) {
         sDurationScale = durationScale;
     }
@@ -268,6 +270,7 @@
     /**
      * @hide
      */
+    @TestApi
     public static float getDurationScale() {
         return sDurationScale;
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2a12ac8..b8c133e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2219,6 +2219,7 @@
      * @throws SecurityException if the calling application does not own an active administrator
      *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
      * @throws IllegalStateException if the calling user is locked or has a managed profile.
+     * @throws IllegalArgumentException if the password does not meet system requirements.
      */
     public boolean resetPassword(String password, int flags) {
         throwIfParentInstance("resetPassword");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3f18ea9..f908abc 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2761,8 +2761,10 @@
      *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
      *  handling management of network connections.
      *  <dt> {@link #WIFI_SERVICE} ("wifi")
-     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
-     * Wi-Fi connectivity.
+     *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
+     *  connectivity.  On releases before NYC, it should only be obtained from an application
+     *  context, and not from any other derived context to avoid memory leaks within the calling
+     *  process.
      *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
      *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
      * Wi-Fi Direct connectivity.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4d9db98..1cf23ae 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4314,6 +4314,14 @@
     public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
 
     /**
+     * Internal flag used to indicate ephemeral applications should not be
+     * considered when resolving the intent.
+     *
+     * @hide
+     */
+    public static final int FLAG_IGNORE_EPHEMERAL = 0x00000200;
+
+    /**
      * If set, the new activity is not kept in the history stack.  As soon as
      * the user navigates away from it, the activity is finished.  This may also
      * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 8a16ac9..6ef7fd2 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.Nullable;
 import android.text.TextUtils;
 import android.os.Parcelable;
 import android.os.Parcel;
@@ -33,6 +34,7 @@
     private final boolean isAlwaysSyncable;
     private final boolean allowParallelSyncs;
     private final String settingsActivity;
+    private final String packageName;
 
     public SyncAdapterType(String authority, String accountType, boolean userVisible,
             boolean supportsUploading) {
@@ -50,6 +52,7 @@
         this.allowParallelSyncs = false;
         this.settingsActivity = null;
         this.isKey = false;
+        this.packageName = null;
     }
 
     /** @hide */
@@ -57,7 +60,8 @@
             boolean supportsUploading,
             boolean isAlwaysSyncable,
             boolean allowParallelSyncs,
-            String settingsActivity) {
+            String settingsActivity,
+            String packageName) {
         if (TextUtils.isEmpty(authority)) {
             throw new IllegalArgumentException("the authority must not be empty: " + authority);
         }
@@ -72,6 +76,7 @@
         this.allowParallelSyncs = allowParallelSyncs;
         this.settingsActivity = settingsActivity;
         this.isKey = false;
+        this.packageName = packageName;
     }
 
     private SyncAdapterType(String authority, String accountType) {
@@ -89,6 +94,7 @@
         this.allowParallelSyncs = false;
         this.settingsActivity = null;
         this.isKey = true;
+        this.packageName = null;
     }
 
     public boolean supportsUploading() {
@@ -148,6 +154,16 @@
         return settingsActivity;
     }
 
+    /**
+     * The package hosting the sync adapter.
+     * @return The package name.
+     *
+     * @hide
+     */
+    public @Nullable String getPackageName() {
+        return packageName;
+    }
+
     public static SyncAdapterType newKey(String authority, String accountType) {
         return new SyncAdapterType(authority, accountType);
     }
@@ -181,6 +197,7 @@
                     + ", isAlwaysSyncable=" + isAlwaysSyncable
                     + ", allowParallelSyncs=" + allowParallelSyncs
                     + ", settingsActivity=" + settingsActivity
+                    + ", packageName=" + packageName
                     + "}";
         }
     }
@@ -201,6 +218,7 @@
         dest.writeInt(isAlwaysSyncable ? 1 : 0);
         dest.writeInt(allowParallelSyncs ? 1 : 0);
         dest.writeString(settingsActivity);
+        dest.writeString(packageName);
     }
 
     public SyncAdapterType(Parcel source) {
@@ -211,6 +229,7 @@
                 source.readInt() != 0,
                 source.readInt() != 0,
                 source.readInt() != 0,
+                source.readString(),
                 source.readString());
     }
 
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 6704b75..ddbdb8a 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -81,7 +81,7 @@
                     sa.getString(com.android.internal.R.styleable
                             .SyncAdapter_settingsActivity);
             return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
-                    isAlwaysSyncable, allowParallelSyncs, settingsActivity);
+                    isAlwaysSyncable, allowParallelSyncs, settingsActivity, packageName);
         } finally {
             sa.recycle();
         }
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index c9be6eda..b5df4d7 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -68,12 +68,6 @@
     public EphemeralResolveInfo ephemeralResolveInfo;
 
     /**
-     * A ResolveInfo that points at the ephemeral installer.
-     * @hide
-     */
-    public ResolveInfo ephemeralInstaller;
-
-    /**
      * The IntentFilter that was matched for this ResolveInfo.
      */
     public IntentFilter filter;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 0c3d4b3..d4dcacc 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -123,10 +123,18 @@
     /**
      * Load a nano app on a specified context hub.
      *
+     * Note that loading is asynchronous.  When we return from this method,
+     * the nano app (probably) hasn't loaded yet.  Assuming a return of 0
+     * from this method, then the final success/failure for the load, along
+     * with the "handle" for the nanoapp, is all delivered in a byte
+     * string via a call to Callback.onMessageReceipt.
+     *
+     * TODO(b/30784270): Provide a better success/failure and "handle" delivery.
+     *
      * @param hubHandle handle of context hub to load the app on.
      * @param app the nanoApp to load on the hub
      *
-     * @return int nanoAppInstance of the loaded nanoApp on success,
+     * @return 0 if the command for loading was sent to the context hub;
      *         -1 otherwise
      *
      * @see NanoApp
@@ -150,9 +158,17 @@
     /**
      * Unload a specified nanoApp
      *
-     * @param nanoAppHandle handle of the nanoApp to load
+     * Note that unloading is asynchronous.  When we return from this method,
+     * the nano app (probably) hasn't unloaded yet.  Assuming a return of 0
+     * from this method, then the final success/failure for the unload is
+     * delivered in a byte string via a call to Callback.onMessageReceipt.
      *
-     * @return int  0 on success, -1 otherwise
+     * TODO(b/30784270): Provide a better success/failure delivery.
+     *
+     * @param nanoAppHandle handle of the nanoApp to unload
+     *
+     * @return 0 if the command for unloading was sent to the context hub;
+     *         -1 otherwise
      */
     public int unloadNanoApp(int nanoAppHandle) {
         int retVal = -1;
@@ -169,6 +185,24 @@
     /**
      * get information about the nano app instance
      *
+     * NOTE: The returned NanoAppInstanceInfo does _not_ contain correct
+     * information for several fields, specifically:
+     * - getName()
+     * - getPublisher()
+     * - getNeededExecMemBytes()
+     * - getNeededReadMemBytes()
+     * - getNeededWriteMemBytes()
+     *
+     * For example, say you call loadNanoApp() with a NanoApp that has
+     * getName() returning "My Name".  Later, if you call getNanoAppInstanceInfo
+     * for that nanoapp, the returned NanoAppInstanceInfo's getName()
+     * method will claim "Preloaded app, unknown", even though you would
+     * have expected "My Name".  For now, as the user, you'll need to
+     * separately track the above fields if they are of interest to you.
+     *
+     * TODO(b/30943489): Have the returned NanoAppInstanceInfo contain the
+     *     correct information.
+     *
      * @param nanoAppHandle handle of the nanoAppInstance
      * @return NanoAppInstanceInfo Information about the nano app instance.
      *
@@ -209,6 +243,14 @@
     /**
      * Send a message to a specific nano app instance on a context hub.
      *
+     * Note that the return value of this method only speaks of success
+     * up to the point of sending this to the Context Hub.  It is not
+     * an assurance that the Context Hub successfully sent this message
+     * on to the nanoapp.  If assurance is desired, a protocol should be
+     * established between your code and the nanoapp, with the nanoapp
+     * sending a confirmation message (which will be reported via
+     * Callback.onMessageReceipt).
+     *
      * @param hubHandle handle of the hub to send the message to
      * @param nanoAppHandle  handle of the nano app to send to
      * @param message Message to be sent
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 062c958..eea2387 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -162,6 +162,28 @@
         msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
 
         long appId = app.getAppId();
+        // TODO(b/30808791): Remove this hack when the NanoApp API is fixed.
+        // Due to a bug in the NanoApp API, only the least significant four
+        // bytes of the app ID can be stored.  The most significant five
+        // bytes of a normal app ID are the "vendor", and thus the most
+        // significant of the bytes we have is the least significant byte
+        // of the vendor.  In the case that byte is the ASCII value for
+        // lower-case 'L', we assume the vendor is supposed to be "Googl"
+        // and fill in the four most significant bytes accordingly.
+        if ((appId >> 32) != 0) {
+            // We're unlikely to notice this warning, but at least
+            // we can avoid running our hack logic.
+            Log.w(TAG, "Code has not been updated since API fix.");
+        } else {
+            // Note: Lower-case 'L', not the number 1.
+            if (((appId >> 24) & 0xFF) == (long)'l') {
+                // Assume we're a Google nanoapp.
+                appId |= ((long)'G') << 56;
+                appId |= ((long)'o') << 48;
+                appId |= ((long)'o') << 40;
+                appId |= ((long)'g') << 32;
+            }
+        }
 
         msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
         msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
@@ -322,9 +344,16 @@
         appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
         appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
 
+        String action;
+        if (mNanoAppHash.containsKey(appInstanceHandle)) {
+            action = "Updated";
+        } else {
+            action = "Added";
+        }
+
         mNanoAppHash.put(appInstanceHandle, appInfo);
-        Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
-              + " version " + appVersion);
+        Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
+              + appId + " version " + appVersion);
 
         return 0;
     }
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index 8db70e9..bf35a3d 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -43,7 +43,8 @@
     private long mAppIdVendorMask;
 
     // Id of the context hub this instance is expected on
-    private int mContextHubId;
+    // TODO: Provide an API which will let us change this HubId.
+    private int mContextHubId = HUB_ANY;
 
     /**
      * Flag indicating any version. With this flag set, all versions shall match provided version.
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index 71a5a88..ac6d83f 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -113,7 +113,12 @@
     }
 
     /**
-     * Set the application version
+     * Get the application version
+     *
+     * NOTE: There is a race condition where shortly after loading, this
+     * may return -1 instead of the correct version.
+     *
+     * TODO(b/30970527): Fix this race condition.
      *
      * @return int - version of the app
      */
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 9cd563e..d570e66 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -175,7 +175,11 @@
 
         if (isNetworkTypeMobile(type)) {
             if (state.subscriberId == null) {
-                Slog.w(TAG, "Active mobile network without subscriber!");
+                if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
+                        state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
+                    Slog.w(TAG, "Active mobile network without subscriber! ni = "
+                            + state.networkInfo);
+                }
             }
 
             subscriberId = state.subscriberId;
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 4f4e722..9a4b599 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -298,12 +298,16 @@
         mWorker = new WorkerRunnable<Params, Result>() {
             public Result call() throws Exception {
                 mTaskInvoked.set(true);
-
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                //noinspection unchecked
-                Result result = doInBackground(mParams);
-                Binder.flushPendingCommands();
-                return postResult(result);
+                Result result = null;
+                try {
+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                    //noinspection unchecked
+                    result = doInBackground(mParams);
+                    Binder.flushPendingCommands();
+                } finally {
+                    postResult(result);
+                }
+                return result;
             }
         };
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 515a91c..79f1151 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5839,6 +5839,8 @@
         /**
          * If nonzero, ANRs in invisible background processes bring up a dialog.
          * Otherwise, the process will be silently killed.
+         *
+         * Also prevents ANRs and crash dialogs from being suppressed.
          * @hide
          */
         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
@@ -6324,6 +6326,13 @@
                 = "demo_user_setup_complete";
 
         /**
+         * Specifies whether the web action API is enabled.
+         *
+         * @hide
+         */
+        public static final String WEB_ACTION_ENABLED = "web_action_enabled";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -8743,6 +8752,16 @@
         public static final String RETAIL_DEMO_MODE_CONSTANTS = "retail_demo_mode_constants";
 
         /**
+         * The reason for the settings database being downgraded. This is only for
+         * troubleshooting purposes and its value should not be interpreted in any way.
+         *
+         * Type: string
+         *
+         * @hide
+         */
+        public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 286e097..f92d83a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -96,6 +96,8 @@
 
     private HwuiContext mHwuiContext;
 
+    private boolean mIsSingleBuffered;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
@@ -158,7 +160,7 @@
         if (surfaceTexture == null) {
             throw new IllegalArgumentException("surfaceTexture must not be null");
         }
-
+        mIsSingleBuffered = surfaceTexture.isSingleBuffered();
         synchronized (mLock) {
             mName = surfaceTexture.toString();
             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
@@ -457,7 +459,10 @@
             // create a new native Surface and return it after reducing
             // the reference count on mNativeObject.  Either way, it is
             // not necessary to call nativeRelease() here.
+            // NOTE: This must be kept synchronized with the native parceling code
+            // in frameworks/native/libs/Surface.cpp
             mName = source.readString();
+            mIsSingleBuffered = source.readInt() != 0;
             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
         }
     }
@@ -468,7 +473,10 @@
             throw new IllegalArgumentException("dest must not be null");
         }
         synchronized (mLock) {
+            // NOTE: This must be kept synchronized with the native parceling code
+            // in frameworks/native/libs/Surface.cpp
             dest.writeString(mName);
+            dest.writeInt(mIsSingleBuffered ? 1 : 0);
             nativeWriteToParcel(mNativeObject, dest);
         }
         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
@@ -531,6 +539,14 @@
     }
 
     /**
+     * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
+     * @hide
+     */
+    public boolean isSingleBuffered() {
+        return mIsSingleBuffered;
+    }
+
+    /**
      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
      * when a SurfaceTexture could not successfully be allocated.
      */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4818910..e0ac7ed 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -193,26 +193,20 @@
     private boolean mGlobalListenersAdded;
 
     public SurfaceView(Context context) {
-        super(context);
-        init();
+        this(context, null);
     }
 
     public SurfaceView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
+        this(context, attrs, 0);
     }
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        init();
+        this(context, attrs, defStyleAttr, 0);
     }
 
     public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        init();
-    }
 
-    private void init() {
         setWillNotDraw(true);
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c42ad2e..908658f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20280,8 +20280,14 @@
                 // remove it from the transparent region.
                 final int[] location = attachInfo.mTransparentLocation;
                 getLocationInWindow(location);
-                region.op(location[0], location[1], location[0] + mRight - mLeft,
-                        location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
+                // When a view has Z value, then it will be better to leave some area below the view
+                // for drawing shadow. The shadow outset is proportional to the Z value. Note that
+                // the bottom part needs more offset than the left, top and right parts due to the
+                // spot light effects.
+                int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
+                region.op(location[0] - shadowOffset, location[1] - shadowOffset,
+                        location[0] + mRight - mLeft + shadowOffset,
+                        location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
             } else {
                 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) {
                     // The SKIP_DRAW flag IS set and the background drawable exists, we remove
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 3ff8d4f..6933efc15 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -6406,16 +6406,28 @@
             return true;
         }
         super.gatherTransparentRegion(region);
-        final View[] children = mChildren;
-        final int count = mChildrenCount;
+        // Instead of naively traversing the view tree, we have to traverse according to the Z
+        // order here. We need to go with the same order as dispatchDraw().
+        // One example is that after surfaceView punch a hole, we will still allow other views drawn
+        // on top of that hole. In this case, those other views should be able to cut the
+        // transparent region into smaller area.
+        final int childrenCount = mChildrenCount;
         boolean noneOfTheChildrenAreTransparent = true;
-        for (int i = 0; i < count; i++) {
-            final View child = children[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
-                if (!child.gatherTransparentRegion(region)) {
-                    noneOfTheChildrenAreTransparent = false;
+        if (childrenCount > 0) {
+            final ArrayList<View> preorderedList = buildOrderedChildList();
+            final boolean customOrder = preorderedList == null
+                    && isChildrenDrawingOrderEnabled();
+            final View[] children = mChildren;
+            for (int i = 0; i < childrenCount; i++) {
+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
+                    if (!child.gatherTransparentRegion(region)) {
+                        noneOfTheChildrenAreTransparent = false;
+                    }
                 }
             }
+            if (preorderedList != null) preorderedList.clear();
         }
         return meOpaque || noneOfTheChildrenAreTransparent;
     }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index b52e4b0..2b3d643 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -507,6 +507,11 @@
          * Retrieves the {@param outBounds} from the stack with id {@param stackId}.
          */
         void getStackBounds(int stackId, Rect outBounds);
+
+        /**
+         * Overrides all currently playing app animations with {@param a}.
+         */
+        void overridePlayingAppAnimationsLw(Animation a);
     }
 
     public interface PointerEventListener {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 6432f70..5935c78 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1547,7 +1547,7 @@
         }
 
         // Let the window manager know to align the top to y.
-        outParams.gravity = Gravity.LEFT | Gravity.TOP;
+        outParams.gravity = computeGravity();
         outParams.width = width;
         outParams.height = height;
 
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index f2fc617..1095978 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,19 +16,19 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
+import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.Widget;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Parcelable.Creator;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.R;
 
 import java.util.Locale;
 
@@ -102,8 +102,8 @@
      * @param hour the hour to set, in the range (0-23)
      * @see #getHour()
      */
-    public void setHour(int hour) {
-        mDelegate.setHour(hour);
+    public void setHour(@IntRange(from = 0, to = 23) int hour) {
+        mDelegate.setHour(MathUtils.constrain(hour, 0, 23));
     }
 
     /**
@@ -117,13 +117,13 @@
     }
 
     /**
-     * Sets the currently selected minute..
+     * Sets the currently selected minute.
      *
      * @param minute the minute to set, in the range (0-59)
      * @see #getMinute()
      */
-    public void setMinute(int minute) {
-        mDelegate.setMinute(minute);
+    public void setMinute(@IntRange(from = 0, to = 59) int minute) {
+        mDelegate.setMinute(MathUtils.constrain(minute, 0, 59));
     }
 
     /**
@@ -137,8 +137,9 @@
     }
 
     /**
-     * Sets the current hour.
+     * Sets the currently selected hour using 24-hour time.
      *
+     * @param currentHour the hour to set, in the range (0-23)
      * @deprecated Use {@link #setHour(int)}
      */
     @Deprecated
@@ -147,33 +148,34 @@
     }
 
     /**
-     * @return the current hour in the range (0-23)
+     * @return the currently selected hour, in the range (0-23)
      * @deprecated Use {@link #getHour()}
      */
     @NonNull
     @Deprecated
     public Integer getCurrentHour() {
-        return mDelegate.getHour();
+        return getHour();
     }
 
     /**
-     * Set the current minute (0-59).
+     * Sets the currently selected minute.
      *
+     * @param currentMinute the minute to set, in the range (0-59)
      * @deprecated Use {@link #setMinute(int)}
      */
     @Deprecated
     public void setCurrentMinute(@NonNull Integer currentMinute) {
-        mDelegate.setMinute(currentMinute);
+        setMinute(currentMinute);
     }
 
     /**
-     * @return the current minute
+     * @return the currently selected minute, in the range (0-59)
      * @deprecated Use {@link #getMinute()}
      */
     @NonNull
     @Deprecated
     public Integer getCurrentMinute() {
-        return mDelegate.getMinute();
+        return getMinute();
     }
 
     /**
@@ -256,10 +258,10 @@
      * for the real behavior.
      */
     interface TimePickerDelegate {
-        void setHour(int hour);
+        void setHour(@IntRange(from = 0, to = 23) int hour);
         int getHour();
 
-        void setMinute(int minute);
+        void setMinute(@IntRange(from = 0, to = 59) int minute);
         int getMinute();
 
         void setIs24Hour(boolean is24Hour);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index f084db2..b973324 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -70,46 +70,49 @@
  */
 public class VideoView extends SurfaceView
         implements MediaPlayerControl, SubtitleController.Anchor {
-    private String TAG = "VideoView";
-    // settable by the client
-    private Uri         mUri;
-    private Map<String, String> mHeaders;
+    private static final String TAG = "VideoView";
 
     // all possible internal states
-    private static final int STATE_ERROR              = -1;
-    private static final int STATE_IDLE               = 0;
-    private static final int STATE_PREPARING          = 1;
-    private static final int STATE_PREPARED           = 2;
-    private static final int STATE_PLAYING            = 3;
-    private static final int STATE_PAUSED             = 4;
+    private static final int STATE_ERROR = -1;
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_PREPARING = 1;
+    private static final int STATE_PREPARED = 2;
+    private static final int STATE_PLAYING = 3;
+    private static final int STATE_PAUSED = 4;
     private static final int STATE_PLAYBACK_COMPLETED = 5;
 
+    private final Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks = new Vector<>();
+
+    // settable by the client
+    private Uri mUri;
+    private Map<String, String> mHeaders;
+
     // mCurrentState is a VideoView object's current state.
     // mTargetState is the state that a method caller intends to reach.
     // For instance, regardless the VideoView object's current state,
     // calling pause() intends to bring the object to a target state
     // of STATE_PAUSED.
     private int mCurrentState = STATE_IDLE;
-    private int mTargetState  = STATE_IDLE;
+    private int mTargetState = STATE_IDLE;
 
     // All the stuff we need for playing and showing a video
     private SurfaceHolder mSurfaceHolder = null;
     private MediaPlayer mMediaPlayer = null;
-    private int         mAudioSession;
-    private int         mVideoWidth;
-    private int         mVideoHeight;
-    private int         mSurfaceWidth;
-    private int         mSurfaceHeight;
+    private int mAudioSession;
+    private int mVideoWidth;
+    private int mVideoHeight;
+    private int mSurfaceWidth;
+    private int mSurfaceHeight;
     private MediaController mMediaController;
     private OnCompletionListener mOnCompletionListener;
     private MediaPlayer.OnPreparedListener mOnPreparedListener;
-    private int         mCurrentBufferPercentage;
+    private int mCurrentBufferPercentage;
     private OnErrorListener mOnErrorListener;
-    private OnInfoListener  mOnInfoListener;
-    private int         mSeekWhenPrepared;  // recording the seek position while preparing
-    private boolean     mCanPause;
-    private boolean     mCanSeekBack;
-    private boolean     mCanSeekForward;
+    private OnInfoListener mOnInfoListener;
+    private int mSeekWhenPrepared;  // recording the seek position while preparing
+    private boolean mCanPause;
+    private boolean mCanSeekBack;
+    private boolean mCanSeekForward;
 
     /** Subtitle rendering widget overlaid on top of the video. */
     private RenderingWidget mSubtitleWidget;
@@ -118,13 +121,11 @@
     private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
 
     public VideoView(Context context) {
-        super(context);
-        initVideoView();
+        this(context, null);
     }
 
     public VideoView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
-        initVideoView();
     }
 
     public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -133,7 +134,19 @@
 
     public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        initVideoView();
+
+        mVideoWidth = 0;
+        mVideoHeight = 0;
+
+        getHolder().addCallback(mSHCallback);
+        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        requestFocus();
+
+        mCurrentState = STATE_IDLE;
+        mTargetState = STATE_IDLE;
     }
 
     @Override
@@ -209,19 +222,6 @@
         return getDefaultSize(desiredSize, measureSpec);
     }
 
-    private void initVideoView() {
-        mVideoWidth = 0;
-        mVideoHeight = 0;
-        getHolder().addCallback(mSHCallback);
-        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-        setFocusable(true);
-        setFocusableInTouchMode(true);
-        requestFocus();
-        mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
-        mCurrentState = STATE_IDLE;
-        mTargetState  = STATE_IDLE;
-    }
-
     /**
      * Sets video path.
      *
@@ -294,8 +294,6 @@
         }
     }
 
-    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
-
     public void stopPlayback() {
         if (mMediaPlayer != null) {
             mMediaPlayer.stop();
diff --git a/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
new file mode 100644
index 0000000..62f18ea
--- /dev/null
+++ b/core/java/com/android/internal/graphics/drawable/AnimationScaleListDrawable.java
@@ -0,0 +1,254 @@
+/*
+ * 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.internal.graphics.drawable;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * An internal DrawableContainer class, used to draw different things depending on animation scale.
+ * i.e: animation scale can be 0 in battery saver mode.
+ * This class contains 2 drawable, one is animatable, the other is static. When animation scale is
+ * not 0, the animatable drawable will the drawn. Otherwise, the static drawable will be drawn.
+ * <p>This class implements Animatable since ProgressBar can pick this up similarly as an
+ * AnimatedVectorDrawable.
+ * <p>It can be defined in an XML file with the {@code <AnimationScaleListDrawable>}
+ * element.
+ */
+public class AnimationScaleListDrawable extends DrawableContainer implements Animatable {
+    private static final String TAG = "AnimationScaleListDrawable";
+    private AnimationScaleListState mAnimationScaleListState;
+    private boolean mMutated;
+
+    public AnimationScaleListDrawable() {
+        this(null, null);
+    }
+
+    private AnimationScaleListDrawable(@Nullable AnimationScaleListState state,
+            @Nullable Resources res) {
+        // Every scale list drawable has its own constant state.
+        final AnimationScaleListState newState = new AnimationScaleListState(state, this, res);
+        setConstantState(newState);
+        onStateChange(getState());
+    }
+
+    /**
+     * Set the current drawable according to the animation scale. If scale is 0, then pick the
+     * static drawable, otherwise, pick the animatable drawable.
+     */
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final boolean changed = super.onStateChange(stateSet);
+        int idx = mAnimationScaleListState.getCurrentDrawableIndexBasedOnScale();
+        return selectDrawable(idx) || changed;
+    }
+
+
+    @Override
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(r, theme, attrs,
+                R.styleable.AnimationScaleListDrawable);
+        updateDensity(r);
+        a.recycle();
+
+        inflateChildElements(r, parser, attrs, theme);
+
+        onStateChange(getState());
+    }
+
+    /**
+     * Inflates child elements from XML.
+     */
+    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final AnimationScaleListState state = mAnimationScaleListState;
+        final int innerDepth = parser.getDepth() + 1;
+        int type;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth || !parser.getName().equals("item")) {
+                continue;
+            }
+
+            // Either pick up the android:drawable attribute.
+            final TypedArray a = obtainAttributes(r, theme, attrs,
+                    R.styleable.AnimationScaleListDrawableItem);
+            Drawable dr = a.getDrawable(R.styleable.AnimationScaleListDrawableItem_drawable);
+            a.recycle();
+
+            // Or parse the child element under <item>.
+            if (dr == null) {
+                while ((type = parser.next()) == XmlPullParser.TEXT) {
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException(
+                            parser.getPositionDescription()
+                                    + ": <item> tag requires a 'drawable' attribute or "
+                                    + "child tag defining a drawable");
+                }
+                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+            }
+
+            state.addDrawable(dr);
+        }
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mAnimationScaleListState.mutate();
+            mMutated = true;
+        }
+        return this;
+    }
+
+    @Override
+    public void clearMutated() {
+        super.clearMutated();
+        mMutated = false;
+    }
+
+    @Override
+    public void start() {
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            ((Animatable) dr).start();
+        }
+    }
+
+    @Override
+    public void stop() {
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            ((Animatable) dr).stop();
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        boolean result = false;
+        Drawable dr = getCurrent();
+        if (dr != null && dr instanceof Animatable) {
+            result = ((Animatable) dr).isRunning();
+        }
+        return result;
+    }
+
+    static class AnimationScaleListState extends DrawableContainerState {
+        int[] mThemeAttrs = null;
+        // The index of the last static drawable.
+        int mStaticDrawableIndex = -1;
+        // The index of the last animatable drawable.
+        int mAnimatableDrawableIndex = -1;
+
+        AnimationScaleListState(AnimationScaleListState orig, AnimationScaleListDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
+
+            if (orig != null) {
+                // Perform a shallow copy and rely on mutate() to deep-copy.
+                mThemeAttrs = orig.mThemeAttrs;
+
+                mStaticDrawableIndex = orig.mStaticDrawableIndex;
+                mAnimatableDrawableIndex = orig.mAnimatableDrawableIndex;
+            }
+
+        }
+
+        void mutate() {
+            mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
+        }
+
+        /**
+         * Add the drawable into the container.
+         * This class only keep track one animatable drawable, and one static. If there are multiple
+         * defined in the XML, then pick the last one.
+         */
+        int addDrawable(Drawable drawable) {
+            final int pos = addChild(drawable);
+            if (drawable instanceof Animatable) {
+                mAnimatableDrawableIndex = pos;
+            } else {
+                mStaticDrawableIndex = pos;
+            }
+            return pos;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimationScaleListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimationScaleListDrawable(this, res);
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || super.canApplyTheme();
+        }
+
+        public int getCurrentDrawableIndexBasedOnScale() {
+            if (ValueAnimator.getDurationScale() == 0) {
+                return mStaticDrawableIndex;
+            }
+            return mAnimatableDrawableIndex;
+        }
+    }
+
+    @Override
+    public void applyTheme(@NonNull Theme theme) {
+        super.applyTheme(theme);
+
+        onStateChange(getState());
+    }
+
+    @Override
+    protected void setConstantState(@NonNull DrawableContainerState state) {
+        super.setConstantState(state);
+
+        if (state instanceof AnimationScaleListState) {
+            mAnimationScaleListState = (AnimationScaleListState) state;
+        }
+    }
+}
+
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 83d75fb..e51ad3f 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -28,8 +28,9 @@
      * FLAG_SHOW_ON_LOCK_SCREEN.
      *
      * @param isOccluded Whether the Keyguard is occluded by another window.
+     * @param animate Whether to play an animation for the state change.
      */
-    void setOccluded(boolean isOccluded);
+    void setOccluded(boolean isOccluded, boolean animate);
 
     void addStateMonitorCallback(IKeyguardStateCallback callback);
     void verifyUnlock(IKeyguardExitCallback callback);
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 891c920..9bf0948 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -20,7 +20,9 @@
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
@@ -265,4 +267,92 @@
 
         return 0;
     }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int paddingLeft = mPaddingLeft;
+
+        // Where right end of child should go
+        final int width = right - left;
+        final int childRight = width - mPaddingRight;
+
+        // Space available for child
+        final int childSpace = width - paddingLeft - mPaddingRight;
+
+        final int totalLength = getMeasuredHeight();
+        final int count = getChildCount();
+        final int gravity = getGravity();
+        final int majorGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int minorGravity = gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
+
+        int childTop;
+        switch (majorGravity) {
+            case Gravity.BOTTOM:
+                // totalLength contains the padding already
+                childTop = mPaddingTop + bottom - top - totalLength;
+                break;
+
+            // totalLength contains the padding already
+            case Gravity.CENTER_VERTICAL:
+                childTop = mPaddingTop + (bottom - top - totalLength) / 2;
+                break;
+
+            case Gravity.TOP:
+            default:
+                childTop = mPaddingTop;
+                break;
+        }
+
+        final Drawable dividerDrawable = getDividerDrawable();
+        final int dividerHeight = dividerDrawable == null ?
+                0 : dividerDrawable.getIntrinsicHeight();
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child != null && child.getVisibility() != GONE) {
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+
+                final LinearLayout.LayoutParams lp =
+                        (LinearLayout.LayoutParams) child.getLayoutParams();
+
+                int layoutGravity = lp.gravity;
+                if (layoutGravity < 0) {
+                    layoutGravity = minorGravity;
+                }
+                final int layoutDirection = getLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(
+                        layoutGravity, layoutDirection);
+
+                final int childLeft;
+                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = paddingLeft + ((childSpace - childWidth) / 2)
+                                + lp.leftMargin - lp.rightMargin;
+                        break;
+
+                    case Gravity.RIGHT:
+                        childLeft = childRight - childWidth - lp.rightMargin;
+                        break;
+
+                    case Gravity.LEFT:
+                    default:
+                        childLeft = paddingLeft + lp.leftMargin;
+                        break;
+                }
+
+                if (hasDividerBeforeChildAt(i)) {
+                    childTop += dividerHeight;
+                }
+
+                childTop += lp.topMargin;
+                setChildFrame(child, childLeft, childTop, childWidth, childHeight);
+                childTop += childHeight + lp.bottomMargin;
+            }
+        }
+    }
+
+    private void setChildFrame(View child, int left, int top, int width, int height) {
+        child.layout(left, top, left + width, top + height);
+    }
 }
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index fbc51cd..5a50fbf 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -79,6 +79,9 @@
     private static final String LOG_FILES_FILE = "log-files.xml";
     private static final AtomicFile sFile = new AtomicFile(new File(
             Environment.getDataSystemDirectory(), LOG_FILES_FILE));
+    private static final String LAST_HEADER_FILE = "last-header.txt";
+    private static final File lastHeaderFile = new File(
+            Environment.getDataSystemDirectory(), LAST_HEADER_FILE);
 
     @Override
     public void onReceive(final Context context, Intent intent) {
@@ -113,9 +116,17 @@
         Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
     }
 
-    private void logBootEvents(Context ctx) throws IOException {
-        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
-        final String headers = new StringBuilder(512)
+    private String getPreviousBootHeaders() {
+        try {
+            return FileUtils.readTextFile(lastHeaderFile, 0, null);
+        } catch (IOException e) {
+            Slog.e(TAG, "Error reading " + lastHeaderFile, e);
+            return null;
+        }
+    }
+
+    private String getCurrentBootHeaders() throws IOException {
+        return new StringBuilder(512)
             .append("Build: ").append(Build.FINGERPRINT).append("\n")
             .append("Hardware: ").append(Build.BOARD).append("\n")
             .append("Revision: ")
@@ -125,6 +136,31 @@
             .append("Kernel: ")
             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
             .append("\n").toString();
+    }
+
+
+    private String getBootHeadersToLogAndUpdate() throws IOException {
+        final String oldHeaders = getPreviousBootHeaders();
+        final String newHeaders = getCurrentBootHeaders();
+
+        try {
+            FileUtils.stringToFile(lastHeaderFile, newHeaders);
+        } catch (IOException e) {
+            Slog.e(TAG, "Error writing " + lastHeaderFile, e);
+        }
+
+        if (oldHeaders == null) {
+            // If we failed to read the old headers, use the current headers
+            // but note this in the headers so we know
+            return "isPrevious: false\n" + newHeaders;
+        }
+
+        return "isPrevious: true\n" + oldHeaders;
+    }
+
+    private void logBootEvents(Context ctx) throws IOException {
+        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
+        final String headers = getBootHeadersToLogAndUpdate();
         final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
 
         String recovery = RecoverySystem.handleAftermath(ctx);
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index d2d39cd..0468b64 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -52,11 +52,9 @@
 } gRectClassInfo;
 
 // Also used in PdfRenderer.cpp
-Mutex sPdfiumLock;
 int sUnmatchedPdfiumInitRequestCount = 0;
 
 static void initializeLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     if (sUnmatchedPdfiumInitRequestCount == 0) {
         FPDF_InitLibrary();
     }
@@ -64,7 +62,6 @@
 }
 
 static void destroyLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     sUnmatchedPdfiumInitRequestCount--;
     if (sUnmatchedPdfiumInitRequestCount == 0) {
        FPDF_DestroyLibrary();
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 71bec78..43550ac 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -44,11 +44,9 @@
 } gPointClassInfo;
 
 // See PdfEditor.cpp
-extern Mutex sPdfiumLock;
 extern int sUnmatchedPdfiumInitRequestCount;
 
 static void initializeLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     if (sUnmatchedPdfiumInitRequestCount == 0) {
         FPDF_InitLibrary();
     }
@@ -56,7 +54,6 @@
 }
 
 static void destroyLibraryIfNeeded() {
-    Mutex::Autolock _l(sPdfiumLock);
     sUnmatchedPdfiumInitRequestCount--;
     if (sUnmatchedPdfiumInitRequestCount == 0) {
        FPDF_DestroyLibrary();
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index bb09d00..e96613b 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -16,6 +16,7 @@
 
 #undef LOG_TAG
 #define LOG_TAG "CursorWindow"
+#define LOG_NDEBUG 0
 
 #include <inttypes.h>
 #include <jni.h>
@@ -30,6 +31,11 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 1
 
 #include <androidfw/CursorWindow.h>
 #include "android_os_Parcel.h"
@@ -61,6 +67,22 @@
     jniThrowException(env, "java/lang/IllegalStateException", msg.string());
 }
 
+static int getFdCount() {
+    char fdpath[PATH_MAX];
+    int count = 0;
+    snprintf(fdpath, PATH_MAX, "/proc/%d/fd", getpid());
+    DIR *dir = opendir(fdpath);
+    if (dir != NULL) {
+        struct dirent *dirent;
+        while ((dirent = readdir(dir))) {
+            count++;
+        }
+        count -= 2; // discount "." and ".."
+        closedir(dir);
+    }
+    return count;
+}
+
 static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
     String8 name;
     const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
@@ -85,7 +107,8 @@
     CursorWindow* window;
     status_t status = CursorWindow::createFromParcel(parcel, &window);
     if (status || !window) {
-        ALOGE("Could not create CursorWindow from Parcel due to error %d.", status);
+        ALOGE("Could not create CursorWindow from Parcel due to error %d, process fd count=%d",
+                status, getFdCount());
         return 0;
     }
 
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 9515a0e..3644410 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -26,6 +26,10 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+
+// TOOD: On master, alphabetize these and move <mutex> into this
+//     grouping.
+#include <chrono>
 #include <unordered_map>
 #include <queue>
 
@@ -34,11 +38,12 @@
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 
-static constexpr int OS_APP_ID = -1;
+static constexpr jint OS_APP_ID = -1;
+static constexpr jint INVALID_APP_ID = -2;
 static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
 
-static constexpr int MIN_APP_ID = 1;
-static constexpr int MAX_APP_ID = 128;
+static constexpr jint MIN_APP_ID = 1;
+static constexpr jint MAX_APP_ID = 128;
 
 static constexpr size_t MSG_HEADER_SIZE = 4;
 static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
@@ -50,6 +55,10 @@
 static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
 static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
 
+// Monotonically increasing clock we use to determine if we can cancel
+// a transaction.
+using std::chrono::steady_clock;
+
 namespace android {
 
 namespace {
@@ -102,10 +111,21 @@
 struct app_instance_info_s {
     uint64_t truncName;          // Possibly truncated name for logging
     uint32_t hubHandle;          // Id of the hub this app is on
-    int instanceId;              // system wide unique instance id - assigned
+    jint instanceId;             // system wide unique instance id - assigned
     struct hub_app_info appInfo; // returned from the HAL
 };
 
+
+// If a transaction takes longer than this, we'll allow it to be
+// canceled by a new transaction.  Note we do _not_ automatically
+// cancel a transaction after this much time.  We can have a
+// legal transaction which takes longer than this amount of time,
+// as long as no other new transactions are attempted after this
+// time has expired.
+// TODO(b/31105001): Establish a clean timing approach for all
+// of our HAL interactions.
+constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
+
 /*
  * TODO(ashutoshj): From original code review:
  *
@@ -147,14 +167,15 @@
     std::mutex m;                 // mutex for manager
     hub_messages_e txnIdentifier; // What are we doing
     void *txnData;                // Details
+    steady_clock::time_point firstTimeTxnCanBeCanceled;
 };
 
 struct contextHubServiceDb_s {
     int initialized;
     context_hub_info_s hubInfo;
     jniInfo_s jniInfo;
-    std::queue<int> freeIds;
-    std::unordered_map<int, app_instance_info_s> appInstances;
+    std::queue<jint> freeIds;
+    std::unordered_map<jint, app_instance_info_s> appInstances;
     txnManager_s txnManager;
 };
 
@@ -176,25 +197,40 @@
     std::lock_guard<std::mutex>lock(mgr->m);
 
     mgr->txnPending = true;
+    mgr->firstTimeTxnCanBeCanceled = steady_clock::now() +
+        kMinTransactionCancelTime;
     mgr->txnData = txnData;
     mgr->txnIdentifier = txnIdentifier;
 
     return 0;
 }
 
-static int closeTxn() {
+// Only call this if you hold the db.txnManager.m lock.
+static void closeTxnUnlocked() {
     txnManager_s *mgr = &db.txnManager;
-    std::lock_guard<std::mutex>lock(mgr->m);
     mgr->txnPending = false;
     free(mgr->txnData);
     mgr->txnData = nullptr;
+}
 
+static int closeTxn() {
+    std::lock_guard<std::mutex>lock(db.txnManager.m);
+    closeTxnUnlocked();
     return 0;
 }
 
+// If a transaction has been pending for longer than
+// kMinTransactionCancelTime, this call will "cancel" that
+// transaction and return that there are none pending.
 static bool isTxnPending() {
     txnManager_s *mgr = &db.txnManager;
     std::lock_guard<std::mutex>lock(mgr->m);
+    if (mgr->txnPending) {
+        if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) {
+            ALOGW("Transaction canceled");
+            closeTxnUnlocked();
+        }
+    }
     return mgr->txnPending;
 }
 
@@ -259,16 +295,17 @@
     }
 }
 
-static int get_hub_handle_for_app_instance(int id) {
+static int get_hub_handle_for_app_instance(jint id) {
     if (!db.appInstances.count(id)) {
-        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+        ALOGD("%s: Cannot find app for app instance %" PRId32,
+              __FUNCTION__, id);
         return -1;
     }
 
     return db.appInstances[id].hubHandle;
 }
 
-static int get_hub_id_for_app_instance(int id) {
+static int get_hub_id_for_app_instance(jint id) {
     int hubHandle = get_hub_handle_for_app_instance(id);
 
     if (hubHandle < 0) {
@@ -278,7 +315,7 @@
     return db.hubInfo.hubs[hubHandle].hub_id;
 }
 
-static int get_app_instance_for_app_id(uint64_t app_id) {
+static jint get_app_instance_for_app_id(uint64_t app_id) {
     auto end = db.appInstances.end();
     for (auto current = db.appInstances.begin(); current != end; ++current) {
         if (current->second.appInfo.app_name.id == app_id) {
@@ -289,9 +326,10 @@
     return -1;
 }
 
-static int set_dest_app(hub_message_t *msg, int id) {
+static int set_dest_app(hub_message_t *msg, jint id) {
     if (!db.appInstances.count(id)) {
-        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
+        ALOGD("%s: Cannot find app for app instance %" PRId32,
+              __FUNCTION__, id);
         return -1;
     }
 
@@ -303,7 +341,7 @@
     hub_message_t msg;
     query_apps_request_t queryMsg;
 
-    queryMsg.app_name.id = NANOAPP_VENDOR_ALL_APPS;
+    queryMsg.app_name.id = appId;
 
     msg.message_type = CONTEXT_HUB_QUERY_APPS;
     msg.message_len  = sizeof(queryMsg);
@@ -322,7 +360,7 @@
     }
 }
 
-static int return_id(int id) {
+static int return_id(jint id) {
     // Note : This method is not thread safe.
     // id returned is guaranteed to be in use
     if (id >= 0) {
@@ -333,9 +371,9 @@
     return -1;
 }
 
-static int generate_id() {
+static jint generate_id() {
     // Note : This method is not thread safe.
-    int retVal = -1;
+    jint retVal = -1;
 
     if (!db.freeIds.empty()) {
         retVal = db.freeIds.front();
@@ -346,8 +384,8 @@
 }
 
 
-static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
-        int appInstanceHandle, JNIEnv *env) {
+static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
+        jint appInstanceHandle, JNIEnv *env) {
 
     ALOGI("Loading App");
 
@@ -355,10 +393,12 @@
     app_instance_info_s entry;
     assert(appInfo);
 
+    const char *action = "Updated";
     if (db.appInstances.count(appInstanceHandle) == 0) {
+        action = "Added";
         appInstanceHandle = generate_id();
         if (appInstanceHandle < 0) {
-            ALOGE("Cannot find resources to add app instance %d",
+            ALOGE("Cannot find resources to add app instance %" PRId32,
                   appInstanceHandle);
             return -1;
         }
@@ -378,36 +418,42 @@
                        hubHandle, entry.instanceId, entry.truncName,
                        entry.appInfo.version);
 
-    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
-          " as appInstance %d", entry.truncName,
+    ALOGW("%s App 0x%" PRIx64 " on hub Handle %" PRId32
+          " as appInstance %" PRId32, action, entry.truncName,
           entry.hubHandle, appInstanceHandle);
 
     return appInstanceHandle;
 }
 
-int delete_app_instance(int id, JNIEnv *env) {
-    if (!db.appInstances.count(id)) {
-        ALOGW("Cannot find App id : %d", id);
-        return -1;
-    }
+int delete_app_instance(jint id, JNIEnv *env) {
+    bool fullyDeleted = true;
 
+    if (db.appInstances.count(id)) {
+        db.appInstances.erase(id);
+    } else {
+        ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
+        fullyDeleted = false;
+    }
     return_id(id);
-    db.appInstances.erase(id);
-    if (env->CallIntMethod(db.jniInfo.jContextHubService,
+
+    if ((env == nullptr) ||
+        (env->CallIntMethod(db.jniInfo.jContextHubService,
                        db.jniInfo.contextHubServiceDeleteAppInstance,
-                       id) != 0) {
-        ALOGW("Could not delete App id : %d", id);
-        return -1;
+                       id) != 0)) {
+        ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
+        fullyDeleted = false;
     }
 
-    ALOGI("Deleted App id : %d", id);
-
-    return 0;
+    if (fullyDeleted) {
+        ALOGI("Deleted App id : %" PRId32, id);
+        return 0;
+    }
+    return -1;
 }
 
 static int startLoadAppTxn(uint64_t appId, int hubHandle) {
     app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
-    int instanceId = generate_id();
+    jint instanceId = generate_id();
 
     if (!txnInfo || instanceId < 0) {
         return_id(instanceId);
@@ -432,8 +478,8 @@
     return 0;
 }
 
-static int startUnloadAppTxn(uint32_t appInstanceHandle) {
-    uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
+static int startUnloadAppTxn(jint appInstanceHandle) {
+    jint *txnData = (jint *) malloc(sizeof(jint));
     if (!txnData) {
         ALOGW("Cannot allocate memory to start unload transaction");
         return -1;
@@ -454,7 +500,6 @@
     int err = 0;
     db.hubInfo.hubs = nullptr;
     db.hubInfo.numHubs = 0;
-    int i;
 
     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
                         (hw_module_t const**)(&db.hubInfo.contextHubModule));
@@ -465,7 +510,7 @@
     }
 
     // Prep for storing app info
-    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+    for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
         db.freeIds.push(i);
     }
 
@@ -485,7 +530,7 @@
                 return;
             }
 
-            for (i = 0; i < db.hubInfo.numHubs; i++) {
+            for (int i = 0; i < db.hubInfo.numHubs; i++) {
                 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
                 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
                 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
@@ -547,13 +592,15 @@
         memcpy(&info, unalignedInfoAddr, sizeof(info));
         // We will only have one instance of the app
         // TODO : Change this logic once we support multiple instances of the same app
-        int appInstance = get_app_instance_for_app_id(info.app_name.id);
+        jint appInstance = get_app_instance_for_app_id(info.app_name.id);
         add_app_instance(&info, hubHandle, appInstance, env);
     }
 
     return 0;
 }
 
+// TODO(b/30807327): Do not use raw bytes for additional data.  Use the
+//     JNI interfaces for the appropriate types.
 static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
                              status_response_t *rsp, int8_t *additionalData,
                              size_t additionalDataLen) {
@@ -584,7 +631,32 @@
     header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
     header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
 
-    msg[0] = rsp->result;
+    // Due to API constraints, at the moment we can't change the fact that
+    // we're changing our 4-byte response to a 1-byte value.  But we can prevent
+    // the possible change in sign (and thus meaning) that would happen from
+    // a naive cast.  Further, we can log when we're losing part of the value.
+    // TODO(b/30918279): Don't truncate this result.
+    int8_t truncatedResult;
+    bool neededToTruncate;
+    if (rsp->result < INT8_MIN) {
+        neededToTruncate = true;
+        truncatedResult = INT8_MIN;
+    } else if (rsp->result > INT8_MAX) {
+        neededToTruncate = true;
+        truncatedResult = INT8_MAX;
+    } else {
+        neededToTruncate = false;
+        // Since this value fits within an int8_t, this is a safe cast which
+        // won't change the value or sign.
+        truncatedResult = static_cast<int8_t>(rsp->result);
+    }
+    if (neededToTruncate) {
+        ALOGW("Response from Context Hub truncated.  Value was %" PRId32
+              ", but giving Java layer %" PRId8,
+              rsp->result, (int)truncatedResult);
+    }
+
+    msg[0] = truncatedResult;
 
     if (additionalData) {
         memcpy(&msg[1], additionalData, additionalDataLen);
@@ -603,6 +675,8 @@
     env->CallIntMethod(db.jniInfo.jContextHubService,
                        db.jniInfo.contextHubServiceMsgReceiptCallback,
                        jheader, jmsg);
+    env->DeleteLocalRef(jmsg);
+    env->DeleteLocalRef(jheader);
 
     delete[] msg;
 }
@@ -613,7 +687,13 @@
 
     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
         txnId == CONTEXT_HUB_UNLOAD_APP) {
-        db.appInstances.erase(*(uint32_t *)txnData);
+        JNIEnv *env;
+        if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
+            ALOGW("Could not attach to JVM !");
+            env = nullptr;
+        }
+        jint handle = *reinterpret_cast<jint *>(txnData);
+        delete_app_instance(handle, env);
     } else {
         ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
     }
@@ -621,7 +701,7 @@
     closeTxn();
 }
 
-void closeLoadTxn(bool success, int *appInstanceHandle) {
+static bool closeLoadTxn(bool success, jint *appInstanceHandle) {
     void *txnData;
     hub_messages_e txnId;
 
@@ -635,13 +715,17 @@
             add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
         } else {
             ALOGW("Could not attach to JVM !");
+            success = false;
         }
         sendQueryForApps(info->appInfo.app_name.id);
     } else {
         ALOGW("Could not load the app successfully ! Unexpected failure");
+        *appInstanceHandle = INVALID_APP_ID;
+        success = false;
     }
 
     closeTxn();
+    return success;
 }
 
 static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
@@ -668,6 +752,7 @@
 
     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
         ALOGW("Could not attach to JVM !");
+        env = nullptr;
     }
 
     auto end = db.appInstances.end();
@@ -697,8 +782,27 @@
       case CONTEXT_HUB_UNLOAD_APP:
           if (isValidOsStatus(msg, msgLen, &rsp)) {
               if (msgType == CONTEXT_HUB_LOAD_APP) {
-                  int appInstanceHandle;
-                  closeLoadTxn(rsp.result == 0, &appInstanceHandle);
+                  jint appInstanceHandle = INVALID_APP_ID;
+                  bool appRunningOnHub = (rsp.result == 0);
+                  if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
+                      if (appRunningOnHub) {
+                          // Now we're in an odd situation.  Our nanoapp
+                          // is up and running on the Context Hub.  However,
+                          // something went wrong in our Service code so that
+                          // we're not able to properly track this nanoapp
+                          // in our Service code.  If we tell the Java layer
+                          // things are good, it's a lie because the handle
+                          // we give them will fail when used with the Service.
+                          // If we tell the Java layer this failed, it's kind
+                          // of a lie as well, since this nanoapp is running.
+                          //
+                          // We leave a more robust fix for later, and for
+                          // now just tell the user things have failed.
+                          //
+                          // TODO(b/30835981): Make this situation better.
+                          rsp.result = -1;
+                      }
+                  }
                   passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
                                    sizeof(appInstanceHandle));
               } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
@@ -778,7 +882,7 @@
     if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
         handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
     } else {
-        int appHandle = get_app_instance_for_app_id(msg->app_name.id);
+        jint appHandle = get_app_instance_for_app_id(msg->app_name.id);
         if (appHandle < 0) {
             ALOGE("Filtering out message due to invalid App Instance.");
         } else {
@@ -1051,7 +1155,8 @@
         ALOGD("Asking HAL to remove app");
         retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
     } else {
-      ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
+      ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32
+            ", setAddress %d",
             header[HEADER_FIELD_APP_INSTANCE],
             header[HEADER_FIELD_HUB_HANDLE],
             (int)setAddressSuccess);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0d8a95c..73b3f52 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -371,7 +371,12 @@
     if (sur != NULL) {
         bufferProducer = sur->getIGraphicBufferProducer();
     }
-    SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
+    status_t err = SurfaceComposerClient::setDisplaySurface(token,
+            bufferProducer);
+    if (err != NO_ERROR) {
+        doThrowIAE(env, "Illegal Surface, could not enable async mode. Was this"
+                " Surface created with singleBufferMode?");
+    }
 }
 
 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index a04fc2a..3207b3c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -54,6 +54,7 @@
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "ScopedUtfChars.h"
+#include "fd_utils-inl.h"
 
 #include "nativebridge/native_bridge.h"
 
@@ -436,6 +437,9 @@
 }
 #endif
 
+// The list of open zygote file descriptors.
+static FileDescriptorTable* gOpenFdTable = NULL;
+
 // Utility routine to fork zygote and specialize the child process.
 static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                      jint debug_flags, jobjectArray javaRlimits,
@@ -450,6 +454,18 @@
   SetForkLoad(true);
 #endif
 
+  // If this is the first fork for this zygote, create the open FD table.
+  // If it isn't, we just need to check whether the list of open files has
+  // changed (and it shouldn't in the normal case).
+  if (gOpenFdTable == NULL) {
+    gOpenFdTable = FileDescriptorTable::Create();
+    if (gOpenFdTable == NULL) {
+      RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
+    }
+  } else if (!gOpenFdTable->Restat()) {
+    RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
+  }
+
   pid_t pid = fork();
 
   if (pid == 0) {
@@ -459,6 +475,12 @@
     // Clean up any descriptors which must be closed immediately
     DetachDescriptors(env, fdsToClose);
 
+    // Re-open all remaining open file descriptors so that they aren't shared
+    // with the zygote across a fork.
+    if (!gOpenFdTable->Reopen()) {
+      RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
+    }
+
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
       EnableKeepCapabilities(env);
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
new file mode 100644
index 0000000..1f34b02
--- /dev/null
+++ b/core/jni/fd_utils-inl.h
@@ -0,0 +1,448 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <unordered_map>
+#include <set>
+#include <vector>
+#include <algorithm>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+#include "JNIHelp.h"
+#include "ScopedPrimitiveArray.h"
+
+// Whitelist of open paths that the zygote is allowed to keep open
+// that will be recreated across forks. In addition to files here,
+// all files ending with ".jar" under /system/framework" are
+// whitelisted. See FileDescriptorInfo::IsWhitelisted for the
+// canonical definition.
+static const char* kPathWhitelist[] = {
+  "/dev/null",
+  "/dev/pmsg0",
+  "/system/etc/event-log-tags",
+  "/sys/kernel/debug/tracing/trace_marker",
+  "/system/framework/framework-res.apk",
+  "/dev/urandom",
+  "/dev/ion"
+};
+
+static const char* kFdPath = "/proc/self/fd";
+
+// Keeps track of all relevant information (flags, offset etc.) of an
+// open zygote file descriptor.
+class FileDescriptorInfo {
+ public:
+  // Create a FileDescriptorInfo for a given file descriptor. Returns
+  // |NULL| if an error occurred.
+  static FileDescriptorInfo* createFromFd(int fd) {
+    struct stat f_stat;
+    // This should never happen; the zygote should always have the right set
+    // of permissions required to stat all its open files.
+    if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
+      ALOGE("Unable to stat fd %d : %s", fd, strerror(errno));
+      return NULL;
+    }
+
+    // Ignore (don't reopen or fail on) socket fds for now.
+    if (S_ISSOCK(f_stat.st_mode)) {
+      ALOGW("Unsupported socket FD: %d, ignoring.", fd);
+      return new FileDescriptorInfo(fd);
+    }
+
+    // We only handle whitelisted regular files and character devices. Whitelisted
+    // character devices must provide a guarantee of sensible behaviour when
+    // reopened.
+    //
+    // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
+    // S_ISLINK : Not supported.
+    // S_ISBLK : Not supported.
+    // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
+    // with the child process across forks but those should have been closed
+    // before we got to this point.
+    if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
+      ALOGE("Unsupported st_mode %d", f_stat.st_mode);
+      return NULL;
+    }
+
+    std::string file_path;
+    if (!Readlink(fd, &file_path)) {
+      return NULL;
+    }
+
+    if (!IsWhitelisted(file_path)) {
+      ALOGE("Not whitelisted : %s", file_path.c_str());
+      return NULL;
+    }
+
+    // File descriptor flags : currently on FD_CLOEXEC. We can set these
+    // using F_SETFD - we're single threaded at this point of execution so
+    // there won't be any races.
+    const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
+    if (fd_flags == -1) {
+      ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno));
+      return NULL;
+    }
+
+    // File status flags :
+    // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
+    //   to the open() call.
+    //
+    // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
+    //   do about these, since the file has already been created. We shall ignore
+    //   them here.
+    //
+    // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
+    //   can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
+    //   In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
+    //   their presence and pass them in to open().
+    int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
+    if (fs_flags == -1) {
+      ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno));
+      return NULL;
+    }
+
+    // File offset : Ignore the offset for non seekable files.
+    const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
+
+    // We pass the flags that open accepts to open, and use F_SETFL for
+    // the rest of them.
+    static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
+    int open_flags = fs_flags & (kOpenFlags);
+    fs_flags = fs_flags & (~(kOpenFlags));
+
+    return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
+  }
+
+  // Checks whether the file descriptor associated with this object
+  // refers to the same description.
+  bool Restat() const {
+    struct stat f_stat;
+    if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
+      return false;
+    }
+
+    return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
+  }
+
+  bool Reopen() const {
+    // Always skip over socket FDs for now.
+    if (is_sock) {
+      return true;
+    }
+
+    // NOTE: This might happen if the file was unlinked after being opened.
+    // It's a common pattern in the case of temporary files and the like but
+    // we should not allow such usage from the zygote.
+    const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
+
+    if (new_fd == -1) {
+      ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno));
+      return false;
+    }
+
+    if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
+      close(new_fd);
+      ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno));
+      return false;
+    }
+
+    if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
+      close(new_fd);
+      ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno));
+      return false;
+    }
+
+    if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
+      close(new_fd);
+      ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno));
+      return false;
+    }
+
+    if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
+      close(new_fd);
+      ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno));
+      return false;
+    }
+
+    if (close(new_fd) == -1) {
+      ALOGW("Failed close(%d) : %s", new_fd, strerror(errno));
+    }
+
+    return true;
+  }
+
+  const int fd;
+  const struct stat stat;
+  const std::string file_path;
+  const int open_flags;
+  const int fd_flags;
+  const int fs_flags;
+  const off_t offset;
+  const bool is_sock;
+
+ private:
+  FileDescriptorInfo(int fd) :
+    fd(fd),
+    stat(),
+    open_flags(0),
+    fd_flags(0),
+    fs_flags(0),
+    offset(0),
+    is_sock(true) {
+  }
+
+  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
+                     int fd_flags, int fs_flags, off_t offset) :
+    fd(fd),
+    stat(stat),
+    file_path(file_path),
+    open_flags(open_flags),
+    fd_flags(fd_flags),
+    fs_flags(fs_flags),
+    offset(offset),
+    is_sock(false) {
+  }
+
+  // Returns true iff. a given path is whitelisted. A path is whitelisted
+  // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
+  // under /system/framework that ends with ".jar".
+  static bool IsWhitelisted(const std::string& path) {
+    for (size_t i = 0; i < (sizeof(kPathWhitelist) / sizeof(kPathWhitelist[0])); ++i) {
+      if (kPathWhitelist[i] == path) {
+        return true;
+      }
+    }
+
+    static const std::string kFrameworksPrefix = "/system/framework/";
+    static const std::string kJarSuffix = ".jar";
+    if (path.compare(0, kFrameworksPrefix.size(), kFrameworksPrefix) == 0 &&
+        path.compare(path.size() - kJarSuffix.size(), kJarSuffix.size(), kJarSuffix) == 0) {
+      return true;
+    }
+    return false;
+  }
+
+  // TODO: Call android::base::Readlink instead of copying the code here.
+  static bool Readlink(const int fd, std::string* result) {
+    char path[64];
+    snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+
+    // Code copied from android::base::Readlink starts here :
+
+    // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
+    // and truncates to whatever size you do supply, so it can't be used to query.
+    // We could call lstat first, but that would introduce a race condition that
+    // we couldn't detect.
+    // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
+    char buf[4096];
+    ssize_t len = readlink(path, buf, sizeof(buf));
+    if (len == -1) return false;
+
+    result->assign(buf, len);
+    return true;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
+};
+
+// A FileDescriptorTable is a collection of FileDescriptorInfo objects
+// keyed by their FDs.
+class FileDescriptorTable {
+ public:
+  // Creates a new FileDescriptorTable. This function scans
+  // /proc/self/fd for the list of open file descriptors and collects
+  // information about them. Returns NULL if an error occurs.
+  static FileDescriptorTable* Create() {
+    DIR* d = opendir(kFdPath);
+    if (d == NULL) {
+      ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
+      return NULL;
+    }
+    int dir_fd = dirfd(d);
+    dirent* e;
+
+    std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
+    while ((e = readdir(d)) != NULL) {
+      const int fd = ParseFd(e, dir_fd);
+      if (fd == -1) {
+        continue;
+      }
+
+      FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
+      if (info == NULL) {
+        if (closedir(d) == -1) {
+          ALOGE("Unable to close directory : %s", strerror(errno));
+        }
+        return NULL;
+      }
+      open_fd_map[fd] = info;
+    }
+
+    if (closedir(d) == -1) {
+      ALOGE("Unable to close directory : %s", strerror(errno));
+      return NULL;
+    }
+    return new FileDescriptorTable(open_fd_map);
+  }
+
+  bool Restat() {
+    std::set<int> open_fds;
+
+    // First get the list of open descriptors.
+    DIR* d = opendir(kFdPath);
+    if (d == NULL) {
+      ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
+      return false;
+    }
+
+    int dir_fd = dirfd(d);
+    dirent* e;
+    while ((e = readdir(d)) != NULL) {
+      const int fd = ParseFd(e, dir_fd);
+      if (fd == -1) {
+        continue;
+      }
+
+      open_fds.insert(fd);
+    }
+
+    if (closedir(d) == -1) {
+      ALOGE("Unable to close directory : %s", strerror(errno));
+      return false;
+    }
+
+    return RestatInternal(open_fds);
+  }
+
+  // Reopens all file descriptors that are contained in the table. Returns true
+  // if all descriptors were re-opened, and false if an error occurred.
+  bool Reopen() {
+    std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
+    for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
+      const FileDescriptorInfo* info = it->second;
+      if (info == NULL || !info->Reopen()) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+ private:
+  FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map)
+      : open_fd_map_(map) {
+  }
+
+  bool RestatInternal(std::set<int>& open_fds) {
+    bool error = false;
+
+    // Iterate through the list of file descriptors we've already recorded
+    // and check whether :
+    //
+    // (a) they continue to be open.
+    // (b) they refer to the same file.
+    std::unordered_map<int, FileDescriptorInfo*>::iterator it;
+    for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
+      std::set<int>::const_iterator element = open_fds.find(it->first);
+      if (element == open_fds.end()) {
+        // The entry from the file descriptor table is no longer in the list
+        // of open files. We warn about this condition and remove it from
+        // the list of FDs under consideration.
+        //
+        // TODO(narayan): This will be an error in a future android release.
+        // error = true;
+        ALOGW("Zygote closed file descriptor %d.", it->first);
+        open_fd_map_.erase(it);
+      } else {
+        // The entry from the file descriptor table is still open. Restat
+        // it and check whether it refers to the same file.
+        open_fds.erase(element);
+        const bool same_file = it->second->Restat();
+        if (!same_file) {
+          // The file descriptor refers to a different description. We must
+          // update our entry in the table.
+          delete it->second;
+          it->second = FileDescriptorInfo::createFromFd(*element);
+          if (it->second == NULL) {
+            // The descriptor no longer no longer refers to a whitelisted file.
+            // We flag an error and remove it from the list of files we're
+            // tracking.
+            error = true;
+            open_fd_map_.erase(it);
+          }
+        } else {
+          // It's the same file. Nothing to do here.
+        }
+      }
+    }
+
+    if (open_fds.size() > 0) {
+      // The zygote has opened new file descriptors since our last inspection.
+      // We warn about this condition and add them to our table.
+      //
+      // TODO(narayan): This will be an error in a future android release.
+      // error = true;
+      ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
+
+      // TODO(narayan): This code will be removed in a future android release.
+      std::set<int>::const_iterator it;
+      for (it = open_fds.begin(); it != open_fds.end(); ++it) {
+        const int fd = (*it);
+        FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
+        if (info == NULL) {
+          // A newly opened file is not on the whitelist. Flag an error and
+          // continue.
+          error = true;
+        } else {
+          // Track the newly opened file.
+          open_fd_map_[fd] = info;
+        }
+      }
+    }
+
+    return !error;
+  }
+
+  static int ParseFd(dirent* e, int dir_fd) {
+    char* end;
+    const int fd = strtol(e->d_name, &end, 10);
+    if ((*end) != '\0') {
+      return -1;
+    }
+
+    // Don't bother with the standard input/output/error, they're handled
+    // specially post-fork anyway.
+    if (fd <= STDERR_FILENO || fd == dir_fd) {
+      return -1;
+    }
+
+    return fd;
+  }
+
+  // Invariant: All values in this unordered_map are non-NULL.
+  std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorTable);
+};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ed71fc2f..6c6fd90 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -183,6 +183,7 @@
     <protected-broadcast
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
     <protected-broadcast android:name="android.btopp.intent.action.LIST" />
@@ -199,6 +200,8 @@
     <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
+    <protected-broadcast android:name="com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT" />
+    <protected-broadcast android:name="com.android.bluetooth.sap.action.DISCONNECT_ACTION" />
 
     <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
 
@@ -394,6 +397,8 @@
 
     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
+    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
+    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
     <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
     <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" />
@@ -1308,6 +1313,7 @@
         android:protectionLevel="dangerous"
         android:description="@string/permdesc_getAccounts"
         android:label="@string/permlab_getAccounts" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
 
     <!-- @SystemApi Allows applications to call into AccountAuthenticators.
     <p>Not for use by third-party applications. -->
@@ -1628,7 +1634,7 @@
 
     <!-- @hide Allows an application to create, remove users and get the list of
          users on the device. Applications holding this permission can only create restricted,
-         guest, managed, and ephemeral users. For creating other kind of users,
+         guest, managed, demo, and ephemeral users. For creating other kind of users,
          {@link android.Manifest.permission#MANAGE_USERS} is needed.
          This permission is not available to third party applications. -->
     <permission android:name="android.permission.CREATE_USERS"
diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml
index 1f67168..1297407 100644
--- a/core/res/res/drawable/ic_refresh.xml
+++ b/core/res/res/drawable/ic_refresh.xml
@@ -21,7 +21,4 @@
     <path
         android:fillColor="#FF000000"
         android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
-    <path
-        android:pathData="M0 0h24v24H0z"
-        android:fillColor="#00000000"/>
 </vector>
diff --git a/core/res/res/drawable/progress_indeterminate_anim_large_material.xml b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
new file mode 100644
index 0000000..560ec5af
--- /dev/null
+++ b/core/res/res/drawable/progress_indeterminate_anim_large_material.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 android:drawable="@drawable/vector_drawable_progress_bar_large" >
+    <target
+            android:name="progressBar"
+            android:animation="@anim/progress_indeterminate_material" />
+
+    <target
+            android:name="root"
+            android:animation="@anim/progress_indeterminate_rotation_material" />
+</animated-vector>
+
diff --git a/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
new file mode 100644
index 0000000..fbea22f
--- /dev/null
+++ b/core/res/res/drawable/progress_indeterminate_anim_medium_material.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
+
+    <target
+        android:name="progressBar"
+        android:animation="@anim/progress_indeterminate_material" />
+
+    <target
+        android:name="root"
+        android:animation="@anim/progress_indeterminate_rotation_material" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/progress_large_material.xml b/core/res/res/drawable/progress_large_material.xml
index 526f914..ee82e35 100644
--- a/core/res/res/drawable/progress_large_material.xml
+++ b/core/res/res/drawable/progress_large_material.xml
@@ -13,16 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_large" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item android:drawable="@drawable/progress_indeterminate_anim_large_material" />
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_medium_material.xml b/core/res/res/drawable/progress_medium_material.xml
index cc35816..5c92600 100644
--- a/core/res/res/drawable/progress_medium_material.xml
+++ b/core/res/res/drawable/progress_medium_material.xml
@@ -13,15 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_medium" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
\ No newline at end of file
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item android:drawable="@drawable/progress_indeterminate_anim_medium_material" />
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_small_material.xml b/core/res/res/drawable/progress_small_material.xml
index c6e4380..cec9d95 100644
--- a/core/res/res/drawable/progress_small_material.xml
+++ b/core/res/res/drawable/progress_small_material.xml
@@ -13,16 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/vector_drawable_progress_bar_small" >
-
-    <target
-        android:name="progressBar"
-        android:animation="@anim/progress_indeterminate_material" />
-
-    <target
-        android:name="root"
-        android:animation="@anim/progress_indeterminate_rotation_material" />
-
-</animated-vector>
+<com.android.internal.graphics.drawable.AnimationScaleListDrawable
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/progress_static_material" />
+    <item>
+        <animated-vector android:drawable="@drawable/vector_drawable_progress_bar_small" >
+            <target
+                    android:name="progressBar"
+                    android:animation="@anim/progress_indeterminate_material" />
+            <target
+                    android:name="root"
+                    android:animation="@anim/progress_indeterminate_rotation_material" />
+        </animated-vector>
+    </item>
+</com.android.internal.graphics.drawable.AnimationScaleListDrawable>
diff --git a/core/res/res/drawable/progress_static_material.xml b/core/res/res/drawable/progress_static_material.xml
new file mode 100644
index 0000000..b078fa9
--- /dev/null
+++ b/core/res/res/drawable/progress_static_material.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        >
+    <path
+        android:fillColor="?attr/colorControlActivated"
+        android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
+</vector>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 8023edf..350caaa 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -598,7 +598,7 @@
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolver chamada"</string>
     <string name="phoneTypeCar" msgid="8738360689616716982">"Coche"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Empresa (ppal.)"</string>
-    <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
+    <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string>
     <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Outro fax"</string>
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index bebe027..10c5836 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1362,7 +1362,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"‏%1$s‏, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‏%1$s‏, %2$s‏, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"אחסון משותף פנימי"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"אחסון שיתוף פנימי"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"‏כרטיס SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏כרטיס SD של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"‏כונן USB"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5b446b4..8bd7160 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1310,7 +1310,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장공간"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장용량"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 카드"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 드라이브"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 0f82dcb..58c2c8a 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1197,8 +1197,7 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Колдонмого орнотуу сеанстарын окуу мүмкүнчүлүгүн берет. Ушуну менен, ал жигердүү топтом орнотууларынын чоо-жайын көрө алат."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнотуу топтомдорун суроо"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Колдонмо топтомдорду орнотууга уруксат сурай алат."</string>
-    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
-    <skip />
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Өтүү"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Издөө"</string>
@@ -1229,10 +1228,8 @@
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Эскертмелердин маанилүүлүгүн баалоо кызматы"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string>
-    <!-- no translation found for vpn_text (1610714069627824309) -->
-    <skip />
-    <!-- no translation found for vpn_text_long (4907843483284977618) -->
-    <skip />
+    <string name="vpn_text" msgid="1610714069627824309">"Тармактын параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
+    <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> сеансына туташуу ишке ашты. Желенин параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Дайым иштеген VPN туташууда…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Дайым иштеген VPN туташтырылды"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string>
diff --git a/core/res/res/values-mcc001/config.xml b/core/res/res/values-mcc001/config.xml
new file mode 100644
index 0000000..93cde03
--- /dev/null
+++ b/core/res/res/values-mcc001/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+<resources>
+    <bool name="config_use_sim_language_file">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc222-mnc10/config.xml b/core/res/res/values-mcc222-mnc10/config.xml
index cd6e8c6..c819de2 100644
--- a/core/res/res/values-mcc222-mnc10/config.xml
+++ b/core/res/res/values-mcc222-mnc10/config.xml
@@ -28,29 +28,4 @@
     <string-array translatable="false" name="config_tether_apndata">
       <item>Tethering Internet,web.omnitel.it,,,,,,,,,222,10,,DUN</item>
     </string-array>
-
-    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
-        <item>21401</item>
-        <item>21402</item>
-        <item>21403</item>
-        <item>21404</item>
-        <item>21405</item>
-        <item>21406</item>
-        <item>21407</item>
-        <item>21408</item>
-        <item>21409</item>
-        <item>21410</item>
-        <item>21411</item>
-        <item>21412</item>
-        <item>21413</item>
-        <item>21414</item>
-        <item>21415</item>
-        <item>21416</item>
-        <item>21417</item>
-        <item>21418</item>
-        <item>21419</item>
-        <item>21420</item>
-        <item>21421</item>
-    </string-array>
-
 </resources>
diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
new file mode 100644
index 0000000..bdf83016
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc10/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23203</item>
+        <item>23205</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml
new file mode 100644
index 0000000..2c14f87
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc13/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23203</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml
new file mode 100644
index 0000000..77f6419
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc500/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml
new file mode 100644
index 0000000..77f6419
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc510/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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.
+ */
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ae115d8..5a356d5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1310,7 +1310,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno partilhado"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Armazen. interno partilhado"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 48e4201..0a96ba3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5313,6 +5313,21 @@
         <attr name="alpha" />
     </declare-styleable>
 
+    <!-- Drawable used to render according to the animation scale. Esp. when it is 0 due to battery
+         saver mode. It should contain one animatable drawable and one static drawable.
+         @hide -->
+    <declare-styleable name="AnimationScaleListDrawable">
+    </declare-styleable>
+
+    <!-- Attributes that can be assigned to a AnimationScaleListDrawable item.
+         @hide -->
+    <declare-styleable name="AnimationScaleListDrawableItem">
+        <!-- Reference to a drawable resource to use for the state. If not
+             given, the drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+    </declare-styleable>
+
+
     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
         <!-- Indicates whether the drawable should intially be visible. -->
@@ -5342,7 +5357,10 @@
         <attr name="innerRadius" format="dimension" />
         <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
         <attr name="thickness" format="dimension" />
-        <!-- Indicates whether the drawable's level affects the way the gradient is drawn. -->
+        <!-- Whether the drawable level value (see
+             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the shape.
+             Scaling behavior depends on the shape type. For "ring", the angle is scaled from 0 to
+             360. For all other types, there is no effect. The default value is true. -->
         <attr name="useLevel" />
         <!-- If set, specifies the color to apply to the drawable as a tint. By default,
              no tint is applied. May be a color state list. -->
@@ -5376,28 +5394,37 @@
     <declare-styleable name="GradientDrawableGradient">
         <!-- Start color of the gradient. -->
         <attr name="startColor" format="color" />
-        <!-- Optional center color. For linear gradients, use centerX or centerY
-             to place the center color. -->
+        <!-- Optional center color. For linear gradients, use centerX or centerY to place the center
+             color. -->
         <attr name="centerColor" format="color" />
         <!-- End color of the gradient. -->
         <attr name="endColor" format="color" />
+        <!-- Whether the drawable level value (see
+             {@link android.graphics.drawable.Drawable#getLevel()}) is used to scale the gradient.
+             Scaling behavior varies based on gradient type. For "linear", adjusts the ending
+             position along the gradient's axis of orientation. For "radial", adjusts the outer
+             radius. For "sweep", adjusts the ending angle. The default value is false. -->
         <attr name="useLevel" format="boolean" />
-        <!-- Angle of the gradient. -->
+        <!-- Angle of the gradient, used only with linear gradient. Must be a multiple of 45 in the
+             range [0, 315]. -->
         <attr name="angle" format="float" />
         <!-- Type of gradient. The default type is linear. -->
         <attr name="type">
-            <!-- Linear gradient. -->
+            <!-- Linear gradient extending across the center point. -->
             <enum name="linear" value="0" />
-            <!-- Radial, or circular, gradient. -->
+            <!-- Radial gradient extending from the center point outward. -->
             <enum name="radial" value="1" />
-            <!-- Sweep, or angled or diamond, gradient. -->
+            <!-- Sweep (or angular) gradient sweeping counter-clockwise around the center point. -->
             <enum name="sweep"  value="2" />
         </attr>
-        <!-- X coordinate of the origin of the gradient within the shape. -->
+        <!-- X-position of the center point of the gradient within the shape as a fraction of the
+             width. The default value is 0.5. -->
         <attr name="centerX" format="float|fraction" />
-        <!-- Y coordinate of the origin of the gradient within the shape. -->
+        <!-- Y-position of the center point of the gradient within the shape as a fraction of the
+             height. The default value is 0.5. -->
         <attr name="centerY" format="float|fraction" />
-        <!-- Radius of the gradient, used only with radial gradient. -->
+        <!-- Radius of the gradient, used only with radial gradient. May be an explicit dimension
+             or a fractional value relative to the shape's minimum dimension. -->
         <attr name="gradientRadius" format="float|fraction|dimension" />
     </declare-styleable>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b80b0a7..55a87ee 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2153,6 +2153,11 @@
     <!-- Flag specifying whether VT is available on device -->
     <bool name="config_device_vt_available">false</bool>
 
+    <!-- Flag specifying whether the device will use the "allow_hold_in_ims_call" carrier config
+         option.  When false, the device will support holding of IMS calls, regardless of the
+         carrier config setting. -->
+    <bool name="config_device_respects_hold_carrier_config">true</bool>
+
     <!-- Flag specifying whether VT should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
@@ -2295,8 +2300,8 @@
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" />
 
-    <!-- set the system language as value of EF LI/EF PL -->
-    <bool name="config_use_sim_language_file">true</bool>
+    <!-- flag to indicate if EF LI/EF PL should be used for system language -->
+    <bool name="config_use_sim_language_file">false</bool>
 
     <!-- Use ERI text for network name on CDMA LTE -->
     <bool name="config_LTE_eri_for_network_name">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 924d338..67ab8cb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1942,6 +1942,7 @@
   <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
   <java-symbol type="anim" name="lock_screen_wallpaper_exit" />
   <java-symbol type="anim" name="launch_task_behind_source" />
+  <java-symbol type="anim" name="wallpaper_open_exit" />
 
   <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
   <java-symbol type="dimen" name="status_bar_icon_size" />
@@ -2211,6 +2212,7 @@
   <java-symbol type="bool" name="config_carrier_volte_provisioned" />
   <java-symbol type="bool" name="config_carrier_volte_tty_supported" />
   <java-symbol type="bool" name="config_device_vt_available" />
+  <java-symbol type="bool" name="config_device_respects_hold_carrier_config" />
   <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="config_device_wfc_ims_available" />
   <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 5c54324..c386108 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -77,6 +77,8 @@
     private long mProducer;
     private long mFrameAvailableListener;
 
+    private boolean mIsSingleBuffered;
+
     /**
      * Callback interface for being notified that a new stream frame is available.
      */
@@ -130,6 +132,7 @@
      */
     public SurfaceTexture(int texName, boolean singleBufferMode) {
         mCreatorLooper = Looper.myLooper();
+        mIsSingleBuffered = singleBufferMode;
         nativeInit(false, texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
     }
 
@@ -157,6 +160,7 @@
      */
     public SurfaceTexture(boolean singleBufferMode) {
         mCreatorLooper = Looper.myLooper();
+        mIsSingleBuffered = singleBufferMode;
         nativeInit(true, 0, singleBufferMode, new WeakReference<SurfaceTexture>(this));
     }
 
@@ -378,6 +382,14 @@
         }
     }
 
+    /**
+     * Returns true if the SurfaceTexture is single-buffered
+     * @hide
+     */
+    public boolean isSingleBuffered() {
+        return mIsSingleBuffered;
+    }
+
     private native void nativeInit(boolean isDetached, int texName,
             boolean singleBufferMode, WeakReference<SurfaceTexture> weakSelf)
             throws Surface.OutOfResourcesException;
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index c836204..0f305f3 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -144,6 +144,55 @@
  *         android:valueType=&quot;pathType&quot;/&gt;
  * &lt;/set&gt;
  * </pre></li>
+ * <p>
+ * Since AAPT tool is now supporting a new format which can bundle several related XML files into
+ * one, we can merge the previous example into one XML file, like this:
+ * </p>
+ * <pre>
+ * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
+ *     &lt;aapt:attr name="android:drawable"&gt;
+ *         &lt;vector
+ *             android:height=&quot;64dp&quot;
+ *             android:width=&quot;64dp&quot;
+ *             android:viewportHeight=&quot;600&quot;
+ *             android:viewportWidth=&quot;600&quot; &gt;
+ *             &lt;group
+ *                 android:name=&quot;rotationGroup&quot;
+ *                 android:pivotX=&quot;300.0&quot;
+ *                 android:pivotY=&quot;300.0&quot;
+ *                 android:rotation=&quot;45.0&quot; &gt;
+ *                 &lt;path
+ *                     android:name=&quot;v&quot;
+ *                     android:fillColor=&quot;#000000&quot;
+ *                     android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
+ *             &lt;/group&gt;
+ *         &lt;/vector&gt;
+ *     &lt;/aapt:attr&gt;
+ *
+ *     &lt;target android:name=&quot;rotationGroup&quot;&gt; *
+ *         &lt;aapt:attr name="android:animation"&gt;
+ *             &lt;objectAnimator
+ *             android:duration=&quot;6000&quot;
+ *             android:propertyName=&quot;rotation&quot;
+ *             android:valueFrom=&quot;0&quot;
+ *             android:valueTo=&quot;360&quot; /&gt;
+ *         &lt;/aapt:attr&gt;
+ *     &lt;/target&gt;
+ *
+ *     &lt;target android:name=&quot;v&quot; &gt;
+ *         &lt;aapt:attr name="android:animation"&gt;
+ *             &lt;set&gt;
+ *                 &lt;objectAnimator
+ *                     android:duration=&quot;3000&quot;
+ *                     android:propertyName=&quot;pathData&quot;
+ *                     android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
+ *                     android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
+ *                     android:valueType=&quot;pathType&quot;/&gt;
+ *             &lt;/set&gt;
+ *         &lt;/aapt:attr&gt;
+ *      &lt;/target&gt;
+ * &lt;/animated-vector&gt;
+ * </pre>
  *
  * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable
  * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 7f3a437..3aca867 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1422,9 +1422,10 @@
     /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
+     * @hide
      */
-    static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
-            @NonNull AttributeSet set, @NonNull int[] attrs) {
+    protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res,
+            @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) {
         if (theme == null) {
             return res.obtainAttributes(set, attrs);
         }
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index cc7f5c7..c7a3c75 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -27,8 +27,8 @@
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
@@ -601,8 +601,9 @@
      * during inflation.
      *
      * @param res the resources used to inflate density-dependent values
+     * @hide
      */
-    final void updateDensity(Resources res) {
+    protected final void updateDensity(Resources res) {
         mDrawableContainerState.updateDensity(res);
     }
 
@@ -711,7 +712,10 @@
         boolean mHasTintList;
         boolean mHasTintMode;
 
-        DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
+        /**
+         * @hide
+         */
+        protected DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
             mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 3dbd2a9..8c633b0 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -475,16 +475,17 @@
     }
 
     /**
-     * Sets the center location in pixels of the gradient. The radius is
-     * honored only when the gradient type is set to {@link #RADIAL_GRADIENT}
-     * or {@link #SWEEP_GRADIENT}.
+     * Sets the position of the center of the gradient as a fraction of the
+     * width and height.
+     * <p>
+     * The default value is (0.5, 0.5).
      * <p>
      * <strong>Note</strong>: changing this property will affect all instances
      * of a drawable loaded from a resource. It is recommended to invoke
      * {@link #mutate()} before changing this property.
      *
-     * @param x the x coordinate of the gradient's center in pixels
-     * @param y the y coordinate of the gradient's center in pixels
+     * @param x the X-position of the center of the gradient
+     * @param y the Y-position of the center of the gradient
      *
      * @see #mutate()
      * @see #setGradientType(int)
@@ -498,9 +499,10 @@
     }
 
     /**
-     * Returns the center X location of this gradient in pixels.
+     * Returns the X-position of the center of the gradient as a fraction of
+     * the width.
      *
-     * @return the center X location of this gradient in pixels
+     * @return the X-position of the center of the gradient
      * @see #setGradientCenter(float, float)
      */
     public float getGradientCenterX() {
@@ -508,9 +510,10 @@
     }
 
     /**
-     * Returns the center Y location of this gradient in pixels.
+     * Returns the Y-position of the center of this gradient as a fraction of
+     * the height.
      *
-     * @return the center Y location of this gradient in pixels
+     * @return the Y-position of the center of the gradient
      * @see #setGradientCenter(float, float)
      */
     public float getGradientCenterY() {
@@ -554,19 +557,43 @@
     }
 
     /**
-     * Sets whether or not this drawable will honor its {@code level} property.
+     * Sets whether this drawable's {@code level} property will be used to
+     * scale the gradient. If a gradient is not used, this property has no
+     * effect.
      * <p>
-     * <strong>Note</strong>: changing this property will affect all instances
+     * Scaling behavior varies based on gradient type:
+     * <ul>
+     *     <li>{@link #LINEAR_GRADIENT} adjusts the ending position along the
+     *         gradient's axis of orientation (see {@link #getOrientation()})
+     *     <li>{@link #RADIAL_GRADIENT} adjusts the outer radius
+     *     <li>{@link #SWEEP_GRADIENT} adjusts the ending angle
+     * <ul>
+     * <p>
+     * The default value for this property is {@code false}.
+     * <p>
+     * <strong>Note</strong>: This property corresponds to the
+     * {@code android:useLevel} attribute on the inner {@code &lt;gradient&gt;}
+     * tag, NOT the {@code android:useLevel} attribute on the outer
+     * {@code &lt;shape&gt;} tag. For example,
+     * <pre>{@code
+     * <shape ...>
+     *     <gradient
+     *         ...
+     *         android:useLevel="true" />
+     * </shape>
+     * }</pre><p>
+     * <strong>Note</strong>: Changing this property will affect all instances
      * of a drawable loaded from a resource. It is recommended to invoke
      * {@link #mutate()} before changing this property.
      *
-     * @param useLevel {@code true} if this drawable should honor its level,
-     *                 {@code false} otherwise
+     * @param useLevel {@code true} if the gradient should be scaled based on
+     *                 level, {@code false} otherwise
      *
      * @see #mutate()
      * @see #setLevel(int)
      * @see #getLevel()
      * @see #getUseLevel()
+     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
      */
     public void setUseLevel(boolean useLevel) {
         mGradientState.mUseLevel = useLevel;
@@ -575,12 +602,13 @@
     }
 
     /**
-     * Returns whether or not this drawable will honor its {@code level}
-     * property.
+     * Returns whether this drawable's {@code level} property will be used to
+     * scale the gradient.
      *
-     * @return {@code true} if this drawable should honor its level,
+     * @return {@code true} if the gradient should be scaled based on level,
      *         {@code false} otherwise
      * @see #setUseLevel(boolean)
+     * @attr ref android.R.styleable#GradientDrawableGradient_useLevel
      */
     public boolean getUseLevel() {
         return mGradientState.mUseLevel;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 1864206..c30c4c2 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -269,7 +269,8 @@
 
             // If the layer doesn't have a drawable or unresolved theme
             // attribute for a drawable, attempt to parse one from the child
-            // element.
+            // element. If multiple child elements exist, we'll only use the
+            // first one.
             if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
                     layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
                 while ((type = parser.next()) == XmlPullParser.TEXT) {
@@ -279,13 +280,12 @@
                             + ": <item> tag requires a 'drawable' attribute or "
                             + "child tag defining a drawable");
                 }
-                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            }
 
-            if (layer.mDrawable != null) {
+                // We found a child drawable. Take ownership.
+                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
+                layer.mDrawable.setCallback(this);
                 state.mChildrenChangingConfigurations |=
                         layer.mDrawable.getChangingConfigurations();
-                layer.mDrawable.setCallback(this);
             }
 
             addLayer(layer);
@@ -387,7 +387,19 @@
 
         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
         if (dr != null) {
+            if (layer.mDrawable != null) {
+                // It's possible that a drawable was already set, in which case
+                // we should clear the callback. We may have also integrated the
+                // drawable's changing configurations, but we don't have enough
+                // information to revert that change.
+                layer.mDrawable.setCallback(null);
+            }
+
+            // Take ownership of the new drawable.
             layer.mDrawable = dr;
+            layer.mDrawable.setCallback(this);
+            state.mChildrenChangingConfigurations |=
+                    layer.mDrawable.getChangingConfigurations();
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index dc1d18f..9ff6965 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -27,9 +27,9 @@
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Shader;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
@@ -140,12 +140,16 @@
  * in the SVG's path data. This is defined in the viewport space.</dd>
  * <dt><code>android:fillColor</code></dt>
  * <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list
- * or a gradient color. If this property is animated, any value set by the animation will
- * override the original value. No path fill is drawn if this property is not specified.</dd>
+ * or a gradient color (See {@link android.R.styleable#GradientColor}
+ * and {@link android.R.styleable#GradientColorItem}).
+ * If this property is animated, any value set by the animation will override the original value.
+ * No path fill is drawn if this property is not specified.</dd>
  * <dt><code>android:strokeColor</code></dt>
  * <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color
- * state list or a gradient color. If this property is animated, any value set by the animation will
- * override the original value. No path outline is drawn if this property is not specified.</dd>
+ * state list or a gradient color (See {@link android.R.styleable#GradientColor}
+ * and {@link android.R.styleable#GradientColorItem}).
+ * If this property is animated, any value set by the animation will override the original value.
+ * No path outline is drawn if this property is not specified.</dd>
  * <dt><code>android:strokeWidth</code></dt>
  * <dd>The width a path stroke.</dd>
  * <dt><code>android:strokeAlpha</code></dt>
@@ -166,8 +170,9 @@
  * <dt><code>android:strokeMiterLimit</code></dt>
  * <dd>Sets the Miter limit for a stroked path.</dd>
  * <dt><code>android:fillType</code></dt>
- * <dd>Sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
- * For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty</dd>
+ * <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the
+ * same as SVG's "fill-rule" properties. For more details, see
+ * <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd>
  * </dl></dd>
  * </dl>
  *
@@ -201,7 +206,26 @@
  *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
  *     &lt;/group&gt;
  * &lt;/vector&gt;
- * </pre></li>
+ * </pre>
+ * </li>
+ * <li>And here is an example of linear gradient color, which is supported in SDK 24+.
+ * See more details in {@link android.R.styleable#GradientColor} and
+ * {@link android.R.styleable#GradientColorItem}.
+ * <pre>
+ * &lt;gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ *     android:angle="90"
+ *     android:startColor="?android:attr/colorPrimary"
+ *     android:endColor="?android:attr/colorControlActivated"
+ *     android:centerColor="#f00"
+ *     android:startX="0"
+ *     android:startY="0"
+ *     android:endX="100"
+ *     android:endY="100"
+ *     android:type="linear"&gt;
+ * &lt;/gradient&gt;
+ * </pre>
+ * </li>
+ *
  */
 
 public class VectorDrawable extends Drawable {
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 2b70b6a4..cd1f8de 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -79,8 +79,12 @@
         }
 
         mInput = input;
-        mNativeDocument = nativeOpen(mInput.getFd(), size);
-        mPageCount = nativeGetPageCount(mNativeDocument);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            mNativeDocument = nativeOpen(mInput.getFd(), size);
+            mPageCount = nativeGetPageCount(mNativeDocument);
+        }
+
         mCloseGuard.open("close");
     }
 
@@ -102,7 +106,10 @@
     public void removePage(int pageIndex) {
         throwIfClosed();
         throwIfPageNotInDocument(pageIndex);
-        mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
+        }
     }
 
     /**
@@ -125,11 +132,16 @@
         if (clip == null) {
             Point size = new Point();
             getPageSize(pageIndex, size);
-            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
-                    0, 0, size.x, size.y);
+
+            synchronized (PdfRenderer.sPdfiumLock) {
+                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+                        0, 0, size.x, size.y);
+            }
         } else {
-            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
-                    clip.left, clip.top, clip.right, clip.bottom);
+            synchronized (PdfRenderer.sPdfiumLock) {
+                nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+                        clip.left, clip.top, clip.right, clip.bottom);
+            }
         }
     }
 
@@ -143,7 +155,10 @@
         throwIfClosed();
         throwIfOutSizeNull(outSize);
         throwIfPageNotInDocument(pageIndex);
-        nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+        }
     }
 
     /**
@@ -156,7 +171,10 @@
         throwIfClosed();
         throwIfOutMediaBoxNull(outMediaBox);
         throwIfPageNotInDocument(pageIndex);
-        return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+        }
     }
 
     /**
@@ -169,7 +187,10 @@
         throwIfClosed();
         throwIfMediaBoxNull(mediaBox);
         throwIfPageNotInDocument(pageIndex);
-        nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+        }
     }
 
     /**
@@ -182,7 +203,10 @@
         throwIfClosed();
         throwIfOutCropBoxNull(outCropBox);
         throwIfPageNotInDocument(pageIndex);
-        return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+        }
     }
 
     /**
@@ -195,7 +219,10 @@
         throwIfClosed();
         throwIfCropBoxNull(cropBox);
         throwIfPageNotInDocument(pageIndex);
-        nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+        }
     }
 
     /**
@@ -205,7 +232,10 @@
      */
     public boolean shouldScaleForPrinting() {
         throwIfClosed();
-        return nativeScaleForPrinting(mNativeDocument);
+
+        synchronized (PdfRenderer.sPdfiumLock) {
+            return nativeScaleForPrinting(mNativeDocument);
+        }
     }
 
     /**
@@ -219,7 +249,10 @@
     public void write(ParcelFileDescriptor output) throws IOException {
         try {
             throwIfClosed();
-            nativeWrite(mNativeDocument, output.getFd());
+
+            synchronized (PdfRenderer.sPdfiumLock) {
+                nativeWrite(mNativeDocument, output.getFd());
+            }
         } finally {
             IoUtils.closeQuietly(output);
         }
@@ -247,7 +280,9 @@
     }
 
     private void doClose() {
-        nativeClose(mNativeDocument);
+        synchronized (PdfRenderer.sPdfiumLock) {
+            nativeClose(mNativeDocument);
+        }
         IoUtils.closeQuietly(mInput);
         mInput = null;
         mCloseGuard.close();
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 520ebe5..cfc1309 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -99,6 +99,12 @@
  * @see #close()
  */
 public final class PdfRenderer implements AutoCloseable {
+    /**
+     * Any call the native pdfium code has to be single threaded as the library does not support
+     * parallel use.
+     */
+    final static Object sPdfiumLock = new Object();
+
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private final Point mTempPoint = new Point();
@@ -154,8 +160,12 @@
         }
 
         mInput = input;
-        mNativeDocument = nativeCreate(mInput.getFd(), size);
-        mPageCount = nativeGetPageCount(mNativeDocument);
+
+        synchronized (sPdfiumLock) {
+            mNativeDocument = nativeCreate(mInput.getFd(), size);
+            mPageCount = nativeGetPageCount(mNativeDocument);
+        }
+
         mCloseGuard.open("close");
     }
 
@@ -189,7 +199,10 @@
      */
     public boolean shouldScaleForPrinting() {
         throwIfClosed();
-        return nativeScaleForPrinting(mNativeDocument);
+
+        synchronized (sPdfiumLock) {
+            return nativeScaleForPrinting(mNativeDocument);
+        }
     }
 
     /**
@@ -224,7 +237,9 @@
         if (mCurrentPage != null) {
             mCurrentPage.close();
         }
-        nativeClose(mNativeDocument);
+        synchronized (sPdfiumLock) {
+            nativeClose(mNativeDocument);
+        }
         try {
             mInput.close();
         } catch (IOException ioe) {
@@ -277,7 +292,9 @@
 
         private Page(int index) {
             Point size = mTempPoint;
-            mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+            synchronized (sPdfiumLock) {
+                mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+            }
             mIndex = index;
             mWidth = size.x;
             mHeight = size.y;
@@ -384,8 +401,10 @@
 
             final long transformPtr = (transform != null) ? transform.native_instance : 0;
 
-            nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
-                    contentTop, contentRight, contentBottom, transformPtr, renderMode);
+            synchronized (sPdfiumLock) {
+                nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
+                        contentTop, contentRight, contentBottom, transformPtr, renderMode);
+            }
         }
 
         /**
@@ -412,7 +431,9 @@
         }
 
         private void doClose() {
-            nativeClosePage(mNativePage);
+            synchronized (sPdfiumLock) {
+                nativeClosePage(mNativePage);
+            }
             mNativePage = 0;
             mCloseGuard.close();
             mCurrentPage = null;
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index cce58c2..a96ca39 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -20,6 +20,7 @@
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.PendingIntent;
+import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -356,6 +357,9 @@
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
+     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
+     * at any time from the main thread, it is safer to rely on a long-lived context such as one
+     * returned from {@link Context#getApplicationContext()}.
      *
      * @param alias The alias of the desired private key, typically returned via
      *              {@link KeyChainAliasCallback#alias}.
@@ -368,7 +372,7 @@
         if (alias == null) {
             throw new NullPointerException("alias == null");
         }
-        KeyChainConnection keyChainConnection = bind(context);
+        KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
         try {
             final IKeyChainService keyChainService = keyChainConnection.getService();
             final String keyId = keyChainService.requestPrivateKey(alias);
@@ -400,6 +404,9 @@
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
+     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
+     * at any time from the main thread, it is safer to rely on a long-lived context such as one
+     * returned from {@link Context#getApplicationContext()}.
      *
      * @param alias The alias of the desired certificate chain, typically
      * returned via {@link KeyChainAliasCallback#alias}.
@@ -412,7 +419,7 @@
         if (alias == null) {
             throw new NullPointerException("alias == null");
         }
-        KeyChainConnection keyChainConnection = bind(context);
+        KeyChainConnection keyChainConnection = bind(context.getApplicationContext());
         try {
             IKeyChainService keyChainService = keyChainConnection.getService();
 
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4848630b..56af57a 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -679,14 +679,14 @@
             if (value instanceof long[]) {
                 long[] array = (long[]) value;
                 if (array.length == 1) {
-                    return (double) array[0];
+                    return array[0];
                 }
                 throw new NumberFormatException("There are more than one component");
             }
             if (value instanceof int[]) {
                 int[] array = (int[]) value;
                 if (array.length == 1) {
-                    return (double) array[0];
+                    return array[0];
                 }
                 throw new NumberFormatException("There are more than one component");
             }
@@ -1083,6 +1083,7 @@
     private int mThumbnailOffset;
     private int mThumbnailLength;
     private byte[] mThumbnailBytes;
+    private boolean mIsSupportedFile;
 
     // Pattern to check non zero timestamp
     private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
@@ -1472,9 +1473,11 @@
 
             // Process JPEG input stream
             getJpegAttributes(in);
+            mIsSupportedFile = true;
         } catch (IOException e) {
             // Ignore exceptions in order to keep the compatibility with the old versions of
             // ExifInterface.
+            mIsSupportedFile = false;
             Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file"
                     + "(ExifInterface supports JPEG and some RAW image formats only) "
                     + "or a corrupted JPEG file to ExifInterface.", e);
@@ -1553,9 +1556,9 @@
      * and make a single call rather than multiple calls for each attribute.
      */
     public void saveAttributes() throws IOException {
-        if (mIsRaw) {
+        if (!mIsSupportedFile || mIsRaw) {
             throw new UnsupportedOperationException(
-                    "ExifInterface does not support saving attributes on RAW formats.");
+                    "ExifInterface only supports saving attributes on JPEG formats.");
         }
         if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
             throw new UnsupportedOperationException(
@@ -2352,7 +2355,7 @@
         for (int i = 0; i < EXIF_TAGS.length; ++i) {
             int sum = 0;
             for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
-                final ExifAttribute exifAttribute = (ExifAttribute) ((Map.Entry) entry).getValue();
+                final ExifAttribute exifAttribute = (ExifAttribute) entry.getValue();
                 final int size = exifAttribute.size();
                 if (size > 4) {
                     sum += size;
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 883c8c6..b65598c 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -207,7 +207,6 @@
      *         object
      */
     public synchronized int getResponseCode() throws IOException {
-        //avoid dup validateConnection
         if ((mReplyHeader.responseCode == -1)
                 || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
             validateConnection();
@@ -423,8 +422,9 @@
     private void validateConnection() throws IOException {
         ensureOpen();
 
-        // to sure only one privateInput object exist.
-        if (mPrivateInput == null) {
+        // Make sure that a response has been recieved from remote
+        // before continuing
+        if (mPrivateInput == null || mReplyHeader.responseCode == -1) {
             startProcessing();
         }
     }
diff --git a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
index 20173b0..24cbfbd 100644
--- a/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-bn-rBD/strings.xml
@@ -4,7 +4,7 @@
     <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
     <string name="action_use_network" msgid="6076184727448466030">"যেভাবে আছে সেভাবেই এই নেটওয়ার্ক ব্যবহার করুন"</string>
     <string name="action_do_not_use_network" msgid="4577366536956516683">"এই নেটওয়ার্ক ব্যবহার করবেন না"</string>
-    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন করুন"</string>
+    <string name="action_bar_label" msgid="917235635415966620">"নেটওয়ার্কে প্রবেশ করুন"</string>
     <string name="ssl_error_warning" msgid="6653188881418638872">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন তাতে নিরাপত্তার সমস্যা আছে।"</string>
     <string name="ssl_error_example" msgid="647898534624078900">"উদাহরণস্বরূপ, লগইন পৃষ্ঠাটি প্রদর্শিত প্রতিষ্ঠানের অন্তর্গত নাও হতে পারে৷"</string>
     <string name="ssl_error_continue" msgid="6492718244923937110">"যাই হোক না কেন ব্রাউজারের মাধ্যমে অবিরত রাখুন"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index 14d4e2d..02a9127 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -53,7 +53,8 @@
      */
     public static boolean isTouchType(int toolType) {
         return toolType == MotionEvent.TOOL_TYPE_FINGER
-                || toolType == MotionEvent.TOOL_TYPE_STYLUS;
+                || toolType == MotionEvent.TOOL_TYPE_STYLUS
+                || toolType == MotionEvent.TOOL_TYPE_UNKNOWN;
     }
 
     /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index b82f8dd..ae8938d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -401,8 +401,13 @@
                 return true;
             }
 
-            // Open the Close drawer if it is closed and we're at the top of a root.
-            if (size <= 1) {
+            final Intent intent = getIntent();
+            final boolean launchedExternally = intent != null && intent.getData() != null
+                    && mState.action == State.ACTION_BROWSE;
+
+            // Open the Close drawer if it is closed and we're at the top of a root, but only when
+            // not launched by another app.
+            if (size <= 1 && !launchedExternally) {
                 mDrawer.setOpen(true);
                 // Remember so we don't just close it again if back is pressed again.
                 mDrawerLastFiddled = System.currentTimeMillis();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index d2e9885e..b3db037 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
 import android.os.UserHandle;
 import android.preference.PreferenceManager;
 
@@ -85,6 +86,15 @@
     public @interface PermissionStatus {}
 
     /**
+     * Clears all preferences associated with a given package.
+     *
+     * <p>Typically called when a package is removed or when user asked to clear its data.
+     */
+    static void clearPackagePreferences(Context context, String packageName) {
+        clearScopedAccessPreferences(context, packageName);
+    }
+
+    /**
      * Methods below are used to keep track of denied user requests on scoped directory access so
      * the dialog is not offered when user checked the 'Do not ask again' box
      *
@@ -108,6 +118,23 @@
       getPrefs(context).edit().putInt(key, status).apply();
     }
 
+    private static void clearScopedAccessPreferences(Context context, String packageName) {
+        final String keySubstring = "|" + packageName + "|";
+        final SharedPreferences prefs = getPrefs(context);
+        Editor editor = null;
+        for (final String key : prefs.getAll().keySet()) {
+            if (key.contains(keySubstring)) {
+                if (editor == null) {
+                    editor = prefs.edit();
+                }
+                editor.remove(key);
+            }
+        }
+        if (editor != null) {
+            editor.apply();
+        }
+    }
+
     private static String getScopedAccessDenialsKey(String packageName, String uuid,
             String directory) {
         final int userId = UserHandle.myUserId();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
index aef63af..fd1183f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
@@ -23,7 +23,7 @@
 import android.net.Uri;
 
 /**
- * Clean up {@link RecentsProvider} when packages are removed.
+ * Cleans up {@link RecentsProvider} and {@link LocalPreferences} when packages are removed.
  */
 public class PackageReceiver extends BroadcastReceiver {
     @Override
@@ -31,15 +31,19 @@
         final ContentResolver resolver = context.getContentResolver();
 
         final String action = intent.getAction();
+        final Uri data = intent.getData();
+        final String packageName = data == null ? null : data.getSchemeSpecificPart();
+
         if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
             resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE, null, null);
-
+            if (packageName != null) {
+                LocalPreferences.clearPackagePreferences(context, packageName);
+            }
         } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
-            final Uri data = intent.getData();
-            if (data != null) {
-                final String packageName = data.getSchemeSpecificPart();
+            if (packageName != null) {
                 resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE_PACKAGE,
                         packageName, null);
+                LocalPreferences.clearPackagePreferences(context, packageName);
             }
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index b7c0a9c..8a6723f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -53,10 +53,13 @@
 import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
 import android.support.v13.view.DragStartHelper;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.OnItemTouchListener;
+import android.support.v7.widget.RecyclerView.Recycler;
 import android.support.v7.widget.RecyclerView.RecyclerListener;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.text.BidiFormatter;
@@ -243,7 +246,40 @@
 
         mRecView.setAdapter(mAdapter);
 
-        mLayout = new GridLayoutManager(getContext(), mColumnCount);
+        // Switch Access Accessibility API needs an {@link AccessibilityDelegate} to know the proper
+        // route when user selects an UI element. It usually guesses this if the element has an
+        // {@link OnClickListener}, but since we do not have one for itemView, we will need to
+        // manually route it to the right behavior. RecyclerView has its own AccessibilityDelegate,
+        // and routes it to its LayoutManager; so we must override the LayoutManager's accessibility
+        // methods to route clicks correctly.
+        mLayout = new GridLayoutManager(getContext(), mColumnCount) {
+            @Override
+            public void onInitializeAccessibilityNodeInfoForItem(
+                    RecyclerView.Recycler recycler, RecyclerView.State state,
+                    View host, AccessibilityNodeInfoCompat info) {
+                super.onInitializeAccessibilityNodeInfoForItem(recycler, state, host, info);
+                info.addAction(AccessibilityActionCompat.ACTION_CLICK);
+            }
+
+            @Override
+            public boolean performAccessibilityActionForItem(
+                    RecyclerView.Recycler recycler, RecyclerView.State state, View view,
+                    int action, Bundle args) {
+                // We are only handling click events; route all other to default implementation
+                if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+                    RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
+                    if (vh instanceof DocumentHolder) {
+                        DocumentHolder dh = (DocumentHolder) vh;
+                        if (dh.mEventListener != null) {
+                            dh.mEventListener.onActivate(dh);
+                            return true;
+                        }
+                    }
+                }
+                return super.performAccessibilityActionForItem(recycler, state, view, action,
+                        args);
+            }
+        };
         SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
         if (lookup != null) {
             mLayout.setSpanSizeLookup(lookup);
@@ -717,63 +753,57 @@
     private void openDocuments(final Selection selected) {
         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN);
 
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                // TODO: Implement support in Files activity for opening multiple docs.
-                BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
-            }
-        }.execute(selected);
+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+        List<DocumentInfo> docs = mModel.getDocuments(selected);
+        // TODO: Implement support in Files activity for opening multiple docs.
+        BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
     }
 
     private void shareDocuments(final Selection selected) {
         Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SHARE);
 
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                Intent intent;
+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+        List<DocumentInfo> docs = mModel.getDocuments(selected);
+        Intent intent;
 
-                // Filter out directories and virtual files - those can't be shared.
-                List<DocumentInfo> docsForSend = new ArrayList<>();
-                for (DocumentInfo doc: docs) {
-                    if (!doc.isDirectory() && !doc.isVirtualDocument()) {
-                        docsForSend.add(doc);
-                    }
-                }
-
-                if (docsForSend.size() == 1) {
-                    final DocumentInfo doc = docsForSend.get(0);
-
-                    intent = new Intent(Intent.ACTION_SEND);
-                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                    intent.addCategory(Intent.CATEGORY_DEFAULT);
-                    intent.setType(doc.mimeType);
-                    intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
-
-                } else if (docsForSend.size() > 1) {
-                    intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
-                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                    intent.addCategory(Intent.CATEGORY_DEFAULT);
-
-                    final ArrayList<String> mimeTypes = new ArrayList<>();
-                    final ArrayList<Uri> uris = new ArrayList<>();
-                    for (DocumentInfo doc : docsForSend) {
-                        mimeTypes.add(doc.mimeType);
-                        uris.add(doc.derivedUri);
-                    }
-
-                    intent.setType(findCommonMimeType(mimeTypes));
-                    intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
-
-                } else {
-                    return;
-                }
-
-                intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
-                startActivity(intent);
+        // Filter out directories and virtual files - those can't be shared.
+        List<DocumentInfo> docsForSend = new ArrayList<>();
+        for (DocumentInfo doc: docs) {
+            if (!doc.isDirectory() && !doc.isVirtualDocument()) {
+                docsForSend.add(doc);
             }
-        }.execute(selected);
+        }
+
+        if (docsForSend.size() == 1) {
+            final DocumentInfo doc = docsForSend.get(0);
+
+            intent = new Intent(Intent.ACTION_SEND);
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            intent.addCategory(Intent.CATEGORY_DEFAULT);
+            intent.setType(doc.mimeType);
+            intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
+
+        } else if (docsForSend.size() > 1) {
+            intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            intent.addCategory(Intent.CATEGORY_DEFAULT);
+
+            final ArrayList<String> mimeTypes = new ArrayList<>();
+            final ArrayList<Uri> uris = new ArrayList<>();
+            for (DocumentInfo doc : docsForSend) {
+                mimeTypes.add(doc.mimeType);
+                uris.add(doc.derivedUri);
+            }
+
+            intent.setType(findCommonMimeType(mimeTypes));
+            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+
+        } else {
+            return;
+        }
+
+        intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
+        startActivity(intent);
     }
 
     private String generateDeleteMessage(final List<DocumentInfo> docs) {
@@ -819,52 +849,51 @@
         assert(!selected.isEmpty());
 
         final DocumentInfo srcParent = getDisplayState().stack.peek();
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(final List<DocumentInfo> docs) {
 
-                TextView message =
-                        (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
-                message.setText(generateDeleteMessage(docs));
+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+        List<DocumentInfo> docs = mModel.getDocuments(selected);
 
-                // This "insta-hides" files that are being deleted, because
-                // the delete operation may be not execute immediately (it
-                // may be queued up on the FileOperationService.)
-                // To hide the files locally, we call the hide method on the adapter
-                // ...which a live object...cannot be parceled.
-                // For that reason, for now, we implement this dialog NOT
-                // as a fragment (which can survive rotation and have its own state),
-                // but as a simple runtime dialog. So rotating a device with an
-                // active delete dialog...results in that dialog disappearing.
-                // We can do better, but don't have cycles for it now.
-                new AlertDialog.Builder(getActivity())
-                    .setView(message)
-                    .setPositiveButton(
-                         android.R.string.yes,
-                         new DialogInterface.OnClickListener() {
-                            public void onClick(DialogInterface dialog, int id) {
-                                // Finish selection mode first which clears selection so we
-                                // don't end up trying to deselect deleted documents.
-                                // This is done here, rather in the onActionItemClicked
-                                // so we can avoid de-selecting items in the case where
-                                // the user cancels the delete.
-                                if (mActionMode != null) {
-                                    mActionMode.finish();
-                                } else {
-                                    Log.w(TAG, "Action mode is null before deleting documents.");
-                                }
-                                // Hide the files in the UI...since the operation
-                                // might be queued up on FileOperationService.
-                                // We're walking a line here.
-                                mAdapter.hide(selected.getAll());
-                                FileOperations.delete(
-                                        getActivity(), docs, srcParent, getDisplayState().stack);
-                            }
-                        })
-                    .setNegativeButton(android.R.string.no, null)
-                    .show();
-            }
-        }.execute(selected);
+        TextView message =
+                (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
+        message.setText(generateDeleteMessage(docs));
+
+        // This "insta-hides" files that are being deleted, because
+        // the delete operation may be not execute immediately (it
+        // may be queued up on the FileOperationService.)
+        // To hide the files locally, we call the hide method on the adapter
+        // ...which a live object...cannot be parceled.
+        // For that reason, for now, we implement this dialog NOT
+        // as a fragment (which can survive rotation and have its own state),
+        // but as a simple runtime dialog. So rotating a device with an
+        // active delete dialog...results in that dialog disappearing.
+        // We can do better, but don't have cycles for it now.
+        new AlertDialog.Builder(getActivity())
+            .setView(message)
+            .setPositiveButton(
+                 android.R.string.yes,
+                 new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int id) {
+                        // Finish selection mode first which clears selection so we
+                        // don't end up trying to deselect deleted documents.
+                        // This is done here, rather in the onActionItemClicked
+                        // so we can avoid de-selecting items in the case where
+                        // the user cancels the delete.
+                        if (mActionMode != null) {
+                            mActionMode.finish();
+                        } else {
+                            Log.w(TAG, "Action mode is null before deleting documents.");
+                        }
+                        // Hide the files in the UI...since the operation
+                        // might be queued up on FileOperationService.
+                        // We're walking a line here.
+                        mAdapter.hide(selected.getAll());
+                        FileOperations.delete(
+                                getActivity(), docs, srcParent, getDisplayState().stack);
+                    }
+                })
+            .setNegativeButton(android.R.string.no, null)
+            .show();
     }
 
     private void transferDocuments(final Selection selected, final @OpType int mode) {
@@ -898,25 +927,21 @@
                 ? R.string.menu_move : R.string.menu_copy;
         intent.putExtra(DocumentsContract.EXTRA_PROMPT, getResources().getString(drawerTitleId));
 
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                // TODO: Can this move to Fragment bundle state?
-                getDisplayState().selectedDocumentsForCopy = docs;
+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+        List<DocumentInfo> docs = mModel.getDocuments(selected);
+        // TODO: Can this move to Fragment bundle state?
+        getDisplayState().selectedDocumentsForCopy = docs;
 
-                // Determine if there is a directory in the set of documents
-                // to be copied? Why? Directory creation isn't supported by some roots
-                // (like Downloads). This informs DocumentsActivity (the "picker")
-                // to restrict available roots to just those with support.
-                intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
-                intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
+        // Determine if there is a directory in the set of documents
+        // to be copied? Why? Directory creation isn't supported by some roots
+        // (like Downloads). This informs DocumentsActivity (the "picker")
+        // to restrict available roots to just those with support.
+        intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
+        intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
 
-                // This just identifies the type of request...we'll check it
-                // when we reveive a response.
-                startActivityForResult(intent, REQUEST_COPY_DESTINATION);
-            }
-
-        }.execute(selected);
+        // This just identifies the type of request...we'll check it
+        // when we reveive a response.
+        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
     }
 
     private static boolean hasDirectory(List<DocumentInfo> docs) {
@@ -935,12 +960,9 @@
         // Rename option is only available in menu when 1 document selected
         assert(selected.size() == 1);
 
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
-            }
-        }.execute(selected);
+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+        List<DocumentInfo> docs = mModel.getDocuments(selected);
+        RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
     }
 
     @Override
@@ -1099,19 +1121,17 @@
         }
     }
 
-    void copySelectionToClipboard(Selection selection) {
-        assert(!selection.isEmpty());
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                mClipper.clipDocuments(docs);
-                Activity activity = getActivity();
-                Snackbars.makeSnackbar(activity,
-                        activity.getResources().getQuantityString(
-                                R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
-                        Snackbar.LENGTH_SHORT).show();
-            }
-        }.execute(selection);
+    void copySelectionToClipboard(Selection selected) {
+        assert(!selected.isEmpty());
+
+        // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+        List<DocumentInfo> docs = mModel.getDocuments(selected);
+        mClipper.clipDocuments(docs);
+        Activity activity = getActivity();
+        Snackbars.makeSnackbar(activity,
+                activity.getResources().getQuantityString(
+                        R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
+                Snackbar.LENGTH_SHORT).show();
     }
 
     public void pasteFromClipboard() {
@@ -1420,25 +1440,6 @@
             mShadowView.draw(canvas);
         }
     }
-    /**
-     * Abstract task providing support for loading documents *off*
-     * the main thread. And if it isn't obvious, creating a list
-     * of documents (especially large lists) can be pretty expensive.
-     */
-    private abstract class GetDocumentsTask
-            extends AsyncTask<Selection, Void, List<DocumentInfo>> {
-        @Override
-        protected final List<DocumentInfo> doInBackground(Selection... selected) {
-            return mModel.getDocuments(selected[0]);
-        }
-
-        @Override
-        protected final void onPostExecute(List<DocumentInfo> docs) {
-            onDocumentsReady(docs);
-        }
-
-        abstract void onDocumentsReady(List<DocumentInfo> docs);
-    }
 
     @Override
     public boolean isSelected(String modelId) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index 1118171..1de3bbc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -117,7 +117,9 @@
         byteCopyDocument(src, dest);
 
         // Remove the source document.
-        deleteDocument(src, srcParent);
+        if(!isCanceled()) {
+            deleteDocument(src, srcParent);
+        }
     }
 
     @Override
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 78b9927..7fe0d2f 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -566,6 +566,7 @@
             throws FileNotFoundException {
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
 
+        query = query.toLowerCase();
         final File parent;
         synchronized (mRootsLock) {
             parent = mRoots.get(rootId).path;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index cce619e..4950af3 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -873,7 +873,7 @@
     }
 
     private static int getRootFlags(int[] operationsSupported) {
-        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
+        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY;
         if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
             rootFlag |= Root.FLAG_SUPPORTS_CREATE;
         }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 404047b..8c13c81 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -128,7 +128,7 @@
             cursor.moveToNext();
             assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE,
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
                     getInt(cursor, Root.COLUMN_FLAGS));
             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
             assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 9ed15c8..d19b460 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -210,7 +210,11 @@
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
             assertEquals("1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD |
+                    Root.FLAG_SUPPORTS_CREATE |
+                    Root.FLAG_LOCAL_ONLY,
+                    cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device A Storage A", cursor.getString(3));
             assertEquals("1", cursor.getString(4));
@@ -225,7 +229,8 @@
             cursor.moveToNext();
             cursor.moveToNext();
             assertEquals("2", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY, cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
             assertEquals("2", cursor.getString(4));
@@ -271,7 +276,9 @@
 
             cursor.moveToNext();
             assertEquals("1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
+                    cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device A", cursor.getString(3));
             assertEquals("1", cursor.getString(4));
@@ -279,7 +286,9 @@
 
             cursor.moveToNext();
             assertEquals("2", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
+                    cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
             assertEquals("2", cursor.getString(4));
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 2db6fb0..31a776c 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -16,7 +16,6 @@
 
 <com.android.printspooler.widget.PrintContentView
         xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:printspooler="http://schemas.android.com/apk/res/com.android.printspooler"
     android:id="@+id/options_content"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent">
@@ -28,12 +27,14 @@
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:paddingStart="8dip"
+        android:layout_marginEnd="16dp"
         android:elevation="@dimen/preview_controls_elevation"
         android:background="?android:attr/colorPrimary">
 
         <Spinner
             android:id="@+id/destination_spinner"
-            android:layout_width="@dimen/preview_destination_spinner_width"
+            android:layout_width="wrap_content"
+            android:minWidth="@dimen/preview_destination_spinner_width"
             android:layout_height="wrap_content"
             android:layout_marginTop="4dip"
             android:dropDownWidth="wrap_content"
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index 103c157..0d8a90a 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -16,7 +16,8 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
-      android:layout_height="?android:attr/listPreferredItemHeightSmall"
+      android:layout_height="wrap_content"
+      android:minHeight="?android:attr/listPreferredItemHeightSmall"
       style="?android:attr/spinnerItemStyle"
       android:orientation="horizontal"
       android:gravity="start|center_vertical">
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 3debf8e..d4e7963 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -60,7 +60,7 @@
       <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
+    <string name="printer_info_desc" msgid="7181988788991581654">"此打印机的详细信息"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"无法创建文件"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分打印服务已停用"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7d42211..682af8b 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -863,4 +863,7 @@
     <!-- Label for Help and feedback menu item -->
     <string name="help_feedback_label">Help &amp; feedback</string>
 
+    <!-- Content description for drawer menu button [CHAR_LIMIT=30]-->
+    <string name="content_description_menu_button">Menu</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index b5295da..381f903 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -34,6 +34,8 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MenuItem.OnMenuItemClickListener;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 import java.net.URISyntaxException;
 import java.util.Locale;
@@ -112,6 +114,9 @@
                 helpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
                     @Override
                     public boolean onMenuItemClick(MenuItem item) {
+                        MetricsLogger.action(activity,
+                            MetricsEvent.ACTION_SETTING_HELP_AND_FEEDBACK,
+                            intent.getStringExtra(EXTRA_CONTEXT));
                         try {
                             activity.startActivityForResult(intent, 0);
                         } catch (ActivityNotFoundException exc) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 6658c14..a50b366 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -226,6 +226,7 @@
     public void showMenuIcon() {
         mShowingMenu = true;
         getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
+        getActionBar().setHomeActionContentDescription(R.string.content_description_menu_button);
         getActionBar().setDisplayHomeAsUpEnabled(true);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 284827b..aae9cf6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -29,7 +29,6 @@
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.widget.TextView;
-
 import com.android.settingslib.R;
 
 public class AccessPointPreference extends Preference {
@@ -44,13 +43,14 @@
     private final StateListDrawable mWifiSld;
     private final int mBadgePadding;
     private final UserBadgeCache mBadgeCache;
-
     private TextView mTitleView;
+
     private boolean mForSavedNetworks = false;
     private AccessPoint mAccessPoint;
     private Drawable mBadge;
     private int mLevel;
     private CharSequence mContentDescription;
+    private int mDefaultIconResId;
 
     static final int[] WIFI_CONNECTION_STRENGTH = {
             R.string.accessibility_wifi_one_bar,
@@ -85,6 +85,24 @@
         refresh();
     }
 
+    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
+            int iconResId, boolean forSavedNetworks) {
+        super(context);
+        mBadgeCache = cache;
+        mAccessPoint = accessPoint;
+        mForSavedNetworks = forSavedNetworks;
+        mAccessPoint.setTag(this);
+        mLevel = -1;
+        mDefaultIconResId = iconResId;
+
+        mWifiSld = (StateListDrawable) context.getTheme()
+                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+
+        // Distance from the end of the title at which this AP's user badge should sit.
+        mBadgePadding = context.getResources()
+                .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
+    }
+
     public AccessPoint getAccessPoint() {
         return mAccessPoint;
     }
@@ -112,7 +130,7 @@
 
     protected void updateIcon(int level, Context context) {
         if (level == -1) {
-            setIcon(null);
+            safeSetDefaultIcon();
         } else {
             if (getIcon() == null) {
                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
@@ -124,16 +142,24 @@
                             ? STATE_SECURED
                             : STATE_NONE);
                     Drawable drawable = mWifiSld.getCurrent();
-                    if (!mForSavedNetworks) {
+                    if (!mForSavedNetworks && drawable != null) {
                         setIcon(drawable);
-                    } else {
-                        setIcon(null);
+                        return;
                     }
                 }
+                safeSetDefaultIcon();
             }
         }
     }
 
+    private void safeSetDefaultIcon() {
+        if (mDefaultIconResId != 0) {
+            setIcon(mDefaultIconResId);
+        } else {
+            setIcon(null);
+        }
+    }
+
     protected void updateBadge(Context context) {
         WifiConfiguration config = mAccessPoint.getConfig();
         if (config != null) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 0f7fe6f..a43c398 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -114,7 +114,7 @@
 public class SettingsProvider extends ContentProvider {
     private static final boolean DEBUG = false;
 
-    private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
+    private static final boolean DROP_DATABASE_ON_MIGRATION = true;
 
     private static final String LOG_TAG = "SettingsProvider";
 
@@ -2142,6 +2142,12 @@
 
                     // Now upgrade should work fine.
                     onUpgradeLocked(mUserId, oldVersion, newVersion);
+
+                    // Make a note what happened, so we don't wonder why data was lost
+                    String reason = "Settings rebuilt! Current version: "
+                            + curVersion + " while expected: " + newVersion;
+                    getGlobalSettingsLocked().insertSettingLocked(
+                            Settings.Global.DATABASE_DOWNGRADE_REASON, reason, "android");
                 }
 
                 // Set the global settings version if owner.
@@ -2411,7 +2417,7 @@
                 }
 
                 if (currentVersion != newVersion) {
-                    Slog.w("SettingsProvider", "warning: upgrading settings database to version "
+                    Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
                             + currentVersion + " instead; this is probably a bug", new Throwable());
                     if (DEBUG) {
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 73a0449..81ab2ff 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -12,6 +12,8 @@
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.shell.*
+
 include $(BUILD_PACKAGE)
 
 include $(LOCAL_PATH)/tests/Android.mk
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 8b07599..9fd80d3 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -132,6 +132,7 @@
         if (!getFileForDocId(documentId).delete()) {
             throw new FileNotFoundException("Failed to delete: " + documentId);
         }
+        getContext().getContentResolver().notifyChange(getNotificationUri(), null);
     }
 
     // This is used by BugreportProgressService so that the notification uri shared by
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bdb103a..de25115 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -150,9 +150,6 @@
     <!-- DevicePolicyManager get user restrictions -->
     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
 
-    <!-- Needed for passing extras with intent ACTION_SHOW_ADMIN_SUPPORT_DETAILS -->
-    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
-
     <!-- TV picture-in-picture -->
     <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" />
 
diff --git a/packages/SystemUI/res/values-bs-rBA-land/strings.xml b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
index bdc652a..56a4ad2 100644
--- a/packages/SystemUI/res/values-bs-rBA-land/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA-land/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u pejzažnom prikazu."</string>
+    <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u vodoravnom prikazu."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index d0d6c50..2aad63c 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -32,7 +32,7 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
-    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցի լիցքը սպառվում է"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
diff --git a/packages/SystemUI/res/values-it/strings_car.xml b/packages/SystemUI/res/values-it/strings_car.xml
index ae26c9e..19c4e2b 100644
--- a/packages/SystemUI/res/values-it/strings_car.xml
+++ b/packages/SystemUI/res/values-it/strings_car.xml
@@ -20,5 +20,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="car_lockscreen_disclaimer_title" msgid="7997539137376896441">"Guida in modo sicuro"</string>
-    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente coscienti delle condizioni di guida e rispettare le leggi vigenti. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, non adatte, vietate o implicare l\'attraversamento di confini. Anche le informazioni sulle attività commerciali potrebbero essere imprecise o incomplete. I dati non vengono forniti in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare il dispositivo mobile e non utilizzare app non progettate per Android Auto durante la guida."</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente informati sulle condizioni della strada e rispettare la legislazione vigente. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, inadatte, vietate o richiedere l\'attraversamento di aree amministrative. Anche le informazioni sugli esercizi commerciali potrebbero essere imprecise o incomplete. I dati forniti non sono aggiornati in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare dispositivi mobili e app non destinate ad Android Auto durante la guida."</string>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6c48b25..a670df5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1243,11 +1243,6 @@
     <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
     <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
 
-    <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
-    <string name="overview_nav_bar_gesture">Enable split-screen swipe-up gesture</string>
-    <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
-    <string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string>
-
     <!-- Category in the System UI Tuner settings, where new/experimental
          settings are -->
     <string name="experimental">Experimental</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1ee13e9..1e3b841 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -42,7 +42,7 @@
     </style>
 
     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
-    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+    <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
         <item name="android:statusBarColor">@color/transparent</item>
         <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
index 3c872fa..ce636cd 100644
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -18,11 +18,6 @@
                   xmlns:sysui="http://schemas.android.com/apk/res-auto"
                   android:title="@string/other">
 
-    <com.android.systemui.tuner.TunerSwitch
-            android:key="overview_nav_bar_gesture"
-            android:title="@string/overview_nav_bar_gesture"
-            android:summary="@string/overview_nav_bar_gesture_desc" />
-
     <!-- importance -->
     <Preference
             android:key="power_notification_controls"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 84901ee..b393cf7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -90,10 +90,10 @@
         }
 
         @Override // Binder interface
-        public void setOccluded(boolean isOccluded) {
+        public void setOccluded(boolean isOccluded, boolean animate) {
             Trace.beginSection("KeyguardService.mBinder#setOccluded");
             checkPermission();
-            mKeyguardViewMediator.setOccluded(isOccluded);
+            mKeyguardViewMediator.setOccluded(isOccluded, animate);
             Trace.endSection();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index de0c77b..4449435 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1114,11 +1114,11 @@
     /**
      * Notify us when the keyguard is occluded by another window
      */
-    public void setOccluded(boolean isOccluded) {
+    public void setOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#setOccluded");
         if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
         mHandler.removeMessages(SET_OCCLUDED);
-        Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
+        Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
         mHandler.sendMessage(msg);
         Trace.endSection();
     }
@@ -1126,7 +1126,7 @@
     /**
      * Handles SET_OCCLUDED message sent by setOccluded()
      */
-    private void handleSetOccluded(boolean isOccluded) {
+    private void handleSetOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
         synchronized (KeyguardViewMediator.this) {
             if (mHiding && isOccluded) {
@@ -1137,7 +1137,7 @@
 
             if (mOccluded != isOccluded) {
                 mOccluded = isOccluded;
-                mStatusBarKeyguardViewManager.setOccluded(isOccluded);
+                mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate);
                 updateActivityLockScreenState();
                 adjustStatusBarLocked();
             }
@@ -1468,7 +1468,7 @@
                     break;
                 case SET_OCCLUDED:
                     Trace.beginSection("KeyguardViewMediator#handleMessage SET_OCCLUDED");
-                    handleSetOccluded(msg.arg1 != 0);
+                    handleSetOccluded(msg.arg1 != 0, msg.arg2 != 0);
                     Trace.endSection();
                     break;
                 case KEYGUARD_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index 9403664..9214eef 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -35,4 +35,5 @@
             in Rect initialBounds);
     void onDraggingInRecents(float distanceFromTop);
     void onDraggingInRecentsEnded(float velocity);
+    void showCurrentUserToast(int msgResId, int msgLength);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index e117bfe..7207463 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -18,10 +18,12 @@
 
 import android.app.ActivityManager;
 import android.app.UiModeManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -53,6 +55,7 @@
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -96,7 +99,7 @@
     // and does not reside in the home stack.
     private String mOverrideRecentsPackageName;
 
-    private Handler mHandler;
+    private Handler mHandler = new Handler();
     private RecentsImpl mImpl;
     private int mDraggingInRecentsCurrentUser;
 
@@ -162,6 +165,20 @@
         }
     };
 
+
+    private BroadcastReceiver mSystemUserUnlockedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId != UserHandle.USER_NULL) {
+                    mImpl.onUserUnlocked(userId);
+                }
+            }
+        }
+    };
+
+
     /**
      * Returns the callbacks interface that non-system users can call.
      */
@@ -191,7 +208,7 @@
         sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
         sTaskLoader = new RecentsTaskLoader(mContext);
         sConfiguration = new RecentsConfiguration(mContext);
-        mHandler = new Handler();
+
         UiModeManager uiModeManager = (UiModeManager) mContext.
                 getSystemService(Context.UI_MODE_SERVICE);
         if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
@@ -221,6 +238,12 @@
             // For the system user, initialize an instance of the interface that we can pass to the
             // secondary user
             mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+
+            // Listen for user-unlocked to kick off preloading recents
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_USER_UNLOCKED);
+            mContext.registerReceiverAsUser(mSystemUserUnlockedReceiver, UserHandle.SYSTEM, filter,
+                    null /* permission */, null /* scheduler */);
         } else {
             // For the secondary user, bind to the primary user's service to get a persistent
             // interface to register its implementation and to later update its state
@@ -455,8 +478,8 @@
                 mDraggingInRecentsCurrentUser = currentUser;
                 return true;
             } else {
-                Toast.makeText(mContext, R.string.recents_incompatible_app_message,
-                        Toast.LENGTH_SHORT).show();
+                EventBus.getDefault().send(new ShowUserToastEvent(
+                        R.string.recents_incompatible_app_message, Toast.LENGTH_SHORT));
                 return false;
             }
         } else {
@@ -674,6 +697,27 @@
         mImpl.onConfigurationChanged();
     }
 
+    public final void onBusEvent(ShowUserToastEvent event) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
+            mImpl.onShowCurrentUserToast(event.msgResId, event.msgLength);
+        } else {
+            if (mSystemToUserCallbacks != null) {
+                IRecentsNonSystemUserCallbacks callbacks =
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                if (callbacks != null) {
+                    try {
+                        callbacks.showCurrentUserToast(event.msgResId, event.msgLength);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                } else {
+                    Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                }
+            }
+        }
+    }
+
     /**
      * Attempts to register with the system user.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 2757fc4..a7f2716 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -40,6 +40,7 @@
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
 
+import android.widget.Toast;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.R;
@@ -186,7 +187,7 @@
         reloadResources();
     }
 
-    public void onBootCompleted() {
+    public void onUserUnlocked(int userId) {
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -199,6 +200,10 @@
         loader.loadTasks(mContext, plan, launchOpts);
     }
 
+    public void onBootCompleted() {
+        // Do nothing
+    }
+
     public void onConfigurationChanged() {
         reloadResources();
         mDummyStackView.reloadOnConfigurationChange();
@@ -392,6 +397,10 @@
         EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
     }
 
+    public void onShowCurrentUserToast(int msgResId, int msgLength) {
+        Toast.makeText(mContext, msgResId, msgLength).show();
+    }
+
     /**
      * Transitions to the next recent task in the stack.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
index 60bf760..ff9e89e9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -38,6 +38,7 @@
     private static final int MSG_DOCK_TOP_TASK = 7;
     private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
     private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
+    private static final int MSG_SHOW_USER_TOAST = 10;
 
     private RecentsImpl mImpl;
 
@@ -109,6 +110,11 @@
         mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
     }
 
+    @Override
+    public void showCurrentUserToast(int msgResId, int msgLength) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_USER_TOAST, msgResId, msgLength));
+    }
+
     private final Handler mHandler = new Handler() {
 
         @Override
@@ -147,6 +153,9 @@
                 case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
                     mImpl.onDraggingInRecentsEnded((Float) msg.obj);
                     break;
+                case MSG_SHOW_USER_TOAST:
+                    mImpl.onShowCurrentUserToast(msg.arg1, msg.arg2);
+                    break;
                 default:
                     super.handleMessage(msg);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
new file mode 100644
index 0000000..e2b39c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ShowUserToastEvent.java
@@ -0,0 +1,33 @@
+/*
+ * 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.events.component;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when we want to show a toast for the current user.
+ */
+public class ShowUserToastEvent extends EventBus.Event {
+
+    public final int msgResId;
+    public final int msgLength;
+
+    public ShowUserToastEvent(int msgResId, int msgLength) {
+        this.msgResId = msgResId;
+        this.msgLength = msgLength;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 702b076d..fce7f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -1258,7 +1258,7 @@
         String innerPrefix = prefix + "  ";
 
         writer.print(prefix); writer.print(TAG);
-        writer.write(" numStackTasks="); writer.write(mNumStackTasks);
+        writer.write(" numStackTasks="); writer.print(mNumStackTasks);
         writer.println();
 
         writer.print(innerPrefix);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index 5f083d5..5920f46 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -20,12 +20,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.util.ArraySet;
 import android.widget.Toast;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
+import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
 import com.android.systemui.stackdivider.events.StartedDragingEvent;
@@ -100,9 +102,8 @@
     }
 
     private void activityDismissingDockedStack() {
-        Toast toast = Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
-                Toast.LENGTH_SHORT);
-        toast.show();
+        EventBus.getDefault().send(new ShowUserToastEvent(
+                R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT));
     }
 
     private void showPending() {
@@ -112,7 +113,7 @@
             ActivityOptions options = ActivityOptions.makeBasic();
             options.setLaunchTaskId(mPendingTaskIds.valueAt(i));
             options.setTaskOverlay(true);
-            mContext.startActivity(intent, options.toBundle());
+            mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
         }
         mPendingTaskIds.clear();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 02fdd3f..68de16b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -507,7 +507,7 @@
         int intrinsicHeight = getIntrinsicHeight();
         mIsPinned = pinned;
         if (intrinsicHeight != getIntrinsicHeight()) {
-            notifyHeightChanged(false);
+            notifyHeightChanged(false /* needsAnimation */);
         }
         if (pinned) {
             setIconAnimationRunning(true);
@@ -840,8 +840,6 @@
     }
 
     public void resetHeight() {
-        mMaxExpandHeight = 0;
-        mHeadsUpHeight = 0;
         onHeightReset();
         requestLayout();
     }
@@ -1290,7 +1288,7 @@
         }
         mHeadsUpHeight = headsUpChild.getHeight();
         if (intrinsicBefore != getIntrinsicHeight()) {
-            notifyHeightChanged(false  /* needsAnimation */);
+            notifyHeightChanged(true  /* needsAnimation */);
         }
     }
 
@@ -1398,7 +1396,7 @@
         if (isChildInGroup()) {
             mGroupManager.setGroupExpanded(mStatusBarNotification, true);
         }
-        notifyHeightChanged(false);
+        notifyHeightChanged(false /* needsAnimation */);
     }
 
     public void setChildrenExpanded(boolean expanded, boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
index f98b9e5..df4566b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -27,7 +27,7 @@
 /**
  * Controls how light status bar flag applies to the icons.
  */
-public class LightStatusBarController {
+public class LightStatusBarController implements BatteryController.BatteryStateChangeCallback {
 
     private final StatusBarIconController mIconController;
     private final BatteryController mBatteryController;
@@ -37,6 +37,7 @@
     private int mDockedStackVisibility;
     private boolean mFullscreenLight;
     private boolean mDockedLight;
+    private int mLastStatusBarMode;
 
     private final Rect mLastFullscreenBounds = new Rect();
     private final Rect mLastDockedBounds = new Rect();
@@ -45,6 +46,7 @@
             BatteryController batteryController) {
         mIconController = iconController;
         mBatteryController = batteryController;
+        batteryController.addStateChangedCallback(this);
     }
 
     public void setFingerprintUnlockController(
@@ -73,6 +75,7 @@
         }
         mFullscreenStackVisibility = newFullscreen;
         mDockedStackVisibility = newDocked;
+        mLastStatusBarMode = statusBarMode;
         mLastFullscreenBounds.set(fullscreenStackBounds);
         mLastDockedBounds.set(dockedStackBounds);
     }
@@ -123,4 +126,16 @@
             mIconController.setIconsDark(true, animateChange());
         }
     }
+
+    @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+
+    }
+
+    @Override
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        onSystemUiVisibilityChanged(mFullscreenStackVisibility, mDockedStackVisibility,
+                0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, true /* sbModeChange*/,
+                mLastStatusBarMode);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index af85101..a6a5742 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -92,6 +92,7 @@
      * Whether an instant expand request is currently pending and we are just waiting for layout.
      */
     private boolean mInstantExpanding;
+    private boolean mAnimateAfterExpanding;
 
     PanelBar mBar;
 
@@ -656,7 +657,7 @@
                 vel = 0;
             }
             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
-            if (expandBecauseOfFalsing) {
+            if (vel == 0) {
                 animator.setDuration(350);
             }
         } else {
@@ -870,6 +871,7 @@
         }
 
         mInstantExpanding = true;
+        mAnimateAfterExpanding = animate;
         mUpdateFlingOnLayout = false;
         abortAnimations();
         cancelPeek();
@@ -894,7 +896,7 @@
                         if (mStatusBar.getStatusBarWindow().getHeight()
                                 != mStatusBar.getStatusBarHeight()) {
                             getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                            if (animate) {
+                            if (mAnimateAfterExpanding) {
                                 notifyExpandingStarted();
                                 fling(0, true /* expand */);
                             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 96fb7a8..b1bea02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -279,6 +279,14 @@
      */
     private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
 
+    /**
+     * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode
+     * won't draw anything and uninitialized memory will show through
+     * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
+     * libhwui.
+     */
+    private static final float SRC_MIN_ALPHA = 0.002f;
+
     static {
         boolean onlyCoreApps;
         boolean freeformWindowManagement;
@@ -2209,17 +2217,13 @@
             if (mBackdrop.getVisibility() != View.VISIBLE) {
                 mBackdrop.setVisibility(View.VISIBLE);
                 if (allowEnterAnimation) {
-                    mBackdrop.animate().alpha(1f).withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mStatusBarWindowManager.setBackdropShowing(true);
-                        }
-                    });
+                    mBackdrop.setAlpha(SRC_MIN_ALPHA);
+                    mBackdrop.animate().alpha(1f);
                 } else {
                     mBackdrop.animate().cancel();
                     mBackdrop.setAlpha(1f);
-                    mStatusBarWindowManager.setBackdropShowing(true);
                 }
+                mStatusBarWindowManager.setBackdropShowing(true);
                 metaDataChanged = true;
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading in album artwork");
@@ -2282,11 +2286,7 @@
                 } else {
                     mStatusBarWindowManager.setBackdropShowing(false);
                     mBackdrop.animate()
-                            // Never let the alpha become zero - otherwise the RenderNode
-                            // won't draw anything and uninitialized memory will show through
-                            // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
-                            // libhwui.
-                            .alpha(0.002f)
+                            .alpha(SRC_MIN_ALPHA)
                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
                             .setDuration(300)
                             .setStartDelay(0)
@@ -2301,7 +2301,6 @@
                             });
                     if (mKeyguardFadingAway) {
                         mBackdrop.animate()
-
                                 // Make it disappear faster, as the focus should be on the activity
                                 // behind.
                                 .setDuration(mKeyguardFadingAwayDuration / 2)
@@ -4120,6 +4119,15 @@
     }
 
     /**
+     * Plays the animation when an activity that was occluding Keyguard goes away.
+     */
+    public void animateKeyguardUnoccluding() {
+        mScrimController.animateKeyguardUnoccluding(500);
+        mNotificationPanel.setExpandedFraction(0f);
+        animateExpandNotificationsPanel();
+    }
+
+    /**
      * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
      * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
      * because the launched app crashed or something else went wrong.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 8b87a7f..73a95c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -196,6 +196,14 @@
         }
     }
 
+    public void animateKeyguardUnoccluding(long duration) {
+        mAnimateChange = false;
+        setScrimBehindColor(0f);
+        mAnimateChange = true;
+        scheduleUpdate();
+        mDurationOverride = duration;
+    }
+
     public void animateGoingToFullShade(long delay, long duration) {
         mDurationOverride = duration;
         mAnimationDelay = delay;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index c72f994..def4bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -242,7 +242,7 @@
         return mStatusBarWindowManager.isShowingWallpaper();
     }
 
-    public void setOccluded(boolean occluded) {
+    public void setOccluded(boolean occluded, boolean animate) {
         if (occluded && !mOccluded && mShowing) {
             if (mPhoneStatusBar.isInLaunchTransition()) {
                 mOccluded = true;
@@ -258,9 +258,12 @@
             }
         }
         mOccluded = occluded;
-        mPhoneStatusBar.updateMediaMetaData(false, false);
+        mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
         reset();
+        if (animate && !occluded) {
+            mPhoneStatusBar.animateKeyguardUnoccluding();
+        }
     }
 
     public boolean isOccluded() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 61bac2d..e6066aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -59,6 +59,7 @@
     private AudioManager mAudioManager;
     private boolean mGestureAborted;
     private boolean mLongClicked;
+    private OnClickListener mOnClickListener;
 
     private final Runnable mCheckLongPress = new Runnable() {
         public void run() {
@@ -109,6 +110,12 @@
         mCode = code;
     }
 
+    @Override
+    public void setOnClickListener(OnClickListener onClickListener) {
+        super.setOnClickListener(onClickListener);
+        mOnClickListener = onClickListener;
+    }
+
     public void loadAsync(String uri) {
         new AsyncTask<String, Void, Drawable>() {
             @Override
@@ -190,6 +197,7 @@
                     // Provide the same haptic feedback that the system offers for virtual keys.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                 }
+                playSoundEffect(SoundEffectConstants.CLICK);
                 removeCallbacks(mCheckLongPress);
                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 break;
@@ -215,14 +223,14 @@
                     if (doIt) {
                         sendEvent(KeyEvent.ACTION_UP, 0);
                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-                        playSoundEffect(SoundEffectConstants.CLICK);
                     } else {
                         sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                     }
                 } else {
                     // no key code, just a regular ImageView
-                    if (doIt) {
-                        performClick();
+                    if (doIt && mOnClickListener != null) {
+                        mOnClickListener.onClick(this);
+                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                     }
                 }
                 removeCallbacks(mCheckLongPress);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index c8c4310..d1de38c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -216,7 +216,6 @@
     private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
     private boolean mDontClampNextScroll;
-    private boolean mRequestViewResizeAnimationOnLayout;
     private boolean mNeedViewResizeAnimation;
     private View mExpandedGroupView;
     private boolean mEverythingNeedsAnimation;
@@ -518,10 +517,6 @@
         setMaxLayoutHeight(getHeight());
         updateContentHeight();
         clampScrollPosition();
-        if (mRequestViewResizeAnimationOnLayout) {
-            requestAnimationOnViewResize(null);
-            mRequestViewResizeAnimationOnLayout = false;
-        }
         requestChildrenUpdate();
         updateFirstAndLastBackgroundViews();
     }
@@ -1966,9 +1961,9 @@
     }
 
     private void applyCurrentBackgroundBounds() {
-        if (!mFadingOut) {
-            mScrimController.setExcludedBackgroundArea(mCurrentBounds);
-        }
+        mScrimController.setExcludedBackgroundArea(
+                mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
+                        : mCurrentBounds);
         invalidate();
     }
 
@@ -3104,9 +3099,6 @@
 
     @Override
     public void onReset(ExpandableView view) {
-        if (mIsExpanded && mAnimationsEnabled) {
-            mRequestViewResizeAnimationOnLayout = true;
-        }
         updateAnimationState(view);
         updateChronometerForChild(view);
     }
@@ -3847,11 +3839,7 @@
     }
 
     private void updateFadingState() {
-        if (mFadingOut || mParentFadingOut || mAmbientState.isDark()) {
-            mScrimController.setExcludedBackgroundArea(null);
-        } else {
-            applyCurrentBackgroundBounds();
-        }
+        applyCurrentBackgroundBounds();
         updateSrcDrawing();
     }
 
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index c9c5805..188f8bf 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -58,6 +58,9 @@
 # UI it doesn't own. This is necessary to allow screenshots to be taken
 LOCAL_CERTIFICATE := platform
 
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*
+
 include frameworks/base/packages/SettingsLib/common.mk
 
 include $(BUILD_PACKAGE)
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index 4865e96..e2e1e44 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -25,5 +25,5 @@
     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
     <string name="data_transmitted" msgid="7988167672982199061">"Trimise:"</string>
     <string name="data_received" msgid="4062776929376067820">"Primite:"</string>
-    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> (de) octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g> (de) pachete"</string>
+    <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g>   octeți/<xliff:g id="NUMBER_1">%2$s</xliff:g>   pachete"</string>
 </resources>
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 5099db7..8a0dfe5 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2207,7 +2207,12 @@
     // CATEGORY: SETTINGS
     ACTION_AMBIENT_DISPLAY = 495;
 
+    // ACTION: Settings -> [sub settings activity] -> Options menu -> Help & Support
+    //   SUBTYPE: sub settings classname
+    ACTION_SETTING_HELP_AND_FEEDBACK = 496;
+
     // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 695ea60..8dca14f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2208,6 +2208,8 @@
 
         AccessibilityServiceInfo mAccessibilityServiceInfo;
 
+        // The service that's bound to this instance. Whenever this value is non-null, this
+        // object is registered as a death recipient
         IBinder mService;
 
         IAccessibilityServiceClient mServiceInterface;
@@ -2342,14 +2344,14 @@
                 }
             } else {
                 userState.mBindingServices.add(mComponentName);
-                mService = userState.mUiAutomationServiceClient.asBinder();
                 mMainHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         // Simulate asynchronous connection since in onServiceConnected
                         // we may modify the state data in case of an error but bind is
                         // called while iterating over the data and bad things can happen.
-                        onServiceConnected(mComponentName, mService);
+                        onServiceConnected(mComponentName,
+                                userState.mUiAutomationServiceClient.asBinder());
                     }
                 });
                 userState.mUiAutomationService = this;
@@ -2441,7 +2443,19 @@
         @Override
         public void onServiceConnected(ComponentName componentName, IBinder service) {
             synchronized (mLock) {
-                mService = service;
+                if (mService != service) {
+                    if (mService != null) {
+                        mService.unlinkToDeath(this, 0);
+                    }
+                    mService = service;
+                    try {
+                        mService.linkToDeath(this, 0);
+                    } catch (RemoteException re) {
+                        Slog.e(LOG_TAG, "Failed registering death link");
+                        binderDied();
+                        return;
+                    }
+                }
                 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
                 UserState userState = getUserStateLocked(mUserId);
                 addServiceLocked(this, userState);
@@ -3075,7 +3089,6 @@
         }
 
         public void onAdded() throws RemoteException {
-            linkToOwnDeathLocked();
             final long identity = Binder.clearCallingIdentity();
             try {
                 mWindowManagerService.addWindowToken(mOverlayWindowToken,
@@ -3092,17 +3105,6 @@
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
-            unlinkToOwnDeathLocked();
-        }
-
-        public void linkToOwnDeathLocked() throws RemoteException {
-            mService.linkToDeath(this, 0);
-        }
-
-        public void unlinkToOwnDeathLocked() {
-            if (mService != null) {
-                mService.unlinkToDeath(this, 0);
-            }
         }
 
         public void resetLocked() {
@@ -3115,7 +3117,10 @@
             } catch (RemoteException re) {
                 /* ignore */
             }
-            mService = null;
+            if (mService != null) {
+                mService.unlinkToDeath(this, 0);
+                mService = null;
+            }
             mServiceInterface = null;
         }
 
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 9d3889b..b5fcb5c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2266,6 +2266,7 @@
         pw.print(info.updatePeriodMillis);
         pw.print(" resizeMode=");
         pw.print(info.resizeMode);
+        pw.print(" widgetCategory=");
         pw.print(info.widgetCategory);
         pw.print(" autoAdvanceViewId=");
         pw.print(info.autoAdvanceViewId);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index b5b0cd8..4caeba8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -875,7 +875,7 @@
             return AppOpsManager.MODE_IGNORED;
         }
         synchronized (this) {
-            if (isOpRestricted(uid, code, resolvedPackageName)) {
+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -1024,7 +1024,7 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, packageName)) {
+            if (isOpRestrictedLocked(uid, code, packageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             if (op.duration == -1) {
@@ -1082,7 +1082,7 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, resolvedPackageName)) {
+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1308,7 +1308,7 @@
         return op;
     }
 
-    private boolean isOpRestricted(int uid, int code, String packageName) {
+    private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
         int userHandle = UserHandle.getUserId(uid);
         final int restrictionSetCount = mOpUserRestrictions.size();
 
@@ -2210,25 +2210,33 @@
 
     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
             int userHandle, String[] exceptionPackages) {
-        ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
+        boolean notifyChange = false;
 
-        if (restrictionState == null) {
-            try {
-                restrictionState = new ClientRestrictionState(token);
-            } catch (RemoteException e) {
-                return;
+        synchronized (AppOpsService.this) {
+            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
+
+            if (restrictionState == null) {
+                try {
+                    restrictionState = new ClientRestrictionState(token);
+                } catch (RemoteException e) {
+                    return;
+                }
+                mOpUserRestrictions.put(token, restrictionState);
             }
-            mOpUserRestrictions.put(token, restrictionState);
+
+            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+                notifyChange = true;
+            }
+
+            if (restrictionState.isDefault()) {
+                mOpUserRestrictions.remove(token);
+                restrictionState.destroy();
+            }
         }
 
-        if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+        if (notifyChange) {
             notifyWatchersOfChange(code);
         }
-
-        if (restrictionState.isDefault()) {
-            mOpUserRestrictions.remove(token);
-            restrictionState.destroy();
-        }
     }
 
     private void notifyWatchersOfChange(int code) {
@@ -2263,10 +2271,12 @@
     @Override
     public void removeUser(int userHandle) throws RemoteException {
         checkSystemUid("removeUser");
-        final int tokenCount = mOpUserRestrictions.size();
-        for (int i = tokenCount - 1; i >= 0; i--) {
-            ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
-            opRestrictions.removeUser(userHandle);
+        synchronized (AppOpsService.this) {
+            final int tokenCount = mOpUserRestrictions.size();
+            for (int i = tokenCount - 1; i >= 0; i--) {
+                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
+                opRestrictions.removeUser(userHandle);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index c9bbb76..2f96b20 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -22,6 +22,7 @@
 import android.accounts.AccountAndUser;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
 import android.accounts.AuthenticatorDescription;
 import android.accounts.CantAddAccountActivity;
 import android.accounts.GrantCredentialsPermissionActivity;
@@ -29,11 +30,14 @@
 import android.accounts.IAccountAuthenticatorResponse;
 import android.accounts.IAccountManager;
 import android.accounts.IAccountManagerResponse;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -46,9 +50,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -72,11 +78,14 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 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.Pair;
@@ -86,6 +95,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -237,6 +247,13 @@
             + " AND " + ACCOUNTS_NAME + "=?"
             + " AND " + ACCOUNTS_TYPE + "=?";
 
+    private static final String COUNT_OF_MATCHING_GRANTS_ANY_TOKEN = ""
+            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+            + " AND " + GRANTS_GRANTEE_UID + "=?"
+            + " AND " + ACCOUNTS_NAME + "=?"
+            + " AND " + ACCOUNTS_TYPE + "=?";
+
     private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
             AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
 
@@ -376,6 +393,118 @@
                 }
             }
         }, UserHandle.ALL, userFilter, null, null);
+
+        LocalServices.addService(AccountManagerInternal.class, new AccountManagerInternalImpl());
+
+        // Need to cancel account request notifications if the update/install can access the account
+        new PackageMonitor() {
+            @Override
+            public void onPackageAdded(String packageName, int uid) {
+                // Called on a handler, and running as the system
+                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
+            }
+
+            @Override
+            public void onPackageUpdateFinished(String packageName, int uid) {
+                // Called on a handler, and running as the system
+                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
+            }
+        }.register(mContext, mMessageHandler.getLooper(), UserHandle.ALL, true);
+
+        // Cancel account request notification if an app op was preventing the account access
+        mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
+                new AppOpsManager.OnOpChangedInternalListener() {
+            @Override
+            public void onOpChanged(int op, String packageName) {
+                try {
+                    final int userId = ActivityManager.getCurrentUser();
+                    final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+                    final int mode = mAppOpsManager.checkOpNoThrow(
+                            AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
+                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                        final long identity = Binder.clearCallingIdentity();
+                        try {
+                            cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
+                        } finally {
+                            Binder.restoreCallingIdentity(identity);
+                        }
+                    }
+                } catch (NameNotFoundException e) {
+                    /* ignore */
+                }
+            }
+        });
+
+        // Cancel account request notification if a permission was preventing the account access
+        mPackageManager.addOnPermissionsChangeListener(
+                (int uid) -> {
+            Account[] accounts = null;
+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
+            if (packageNames != null) {
+                final int userId = UserHandle.getUserId(uid);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    for (String packageName : packageNames) {
+                        if (mContext.getPackageManager().checkPermission(
+                                Manifest.permission.GET_ACCOUNTS, packageName)
+                                        != PackageManager.PERMISSION_GRANTED) {
+                            continue;
+                        }
+
+                        if (accounts == null) {
+                            accounts = getAccountsAsUser(null, userId, "android");
+                            if (ArrayUtils.isEmpty(accounts)) {
+                                return;
+                            }
+                        }
+
+                        for (Account account : accounts) {
+                            cancelAccountAccessRequestNotificationIfNeeded(
+                                    account, uid, packageName, true);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        });
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
+            boolean checkAccess) {
+        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
+        for (Account account : accounts) {
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
+        }
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
+            boolean checkAccess) {
+        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
+        for (Account account : accounts) {
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
+        }
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
+            boolean checkAccess) {
+        String[] packageNames = mPackageManager.getPackagesForUid(uid);
+        if (packageNames != null) {
+            for (String packageName : packageNames) {
+                cancelAccountAccessRequestNotificationIfNeeded(account, uid,
+                        packageName, checkAccess);
+            }
+        }
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
+            int uid, String packageName, boolean checkAccess) {
+        if (!checkAccess || hasAccountAccess(account, packageName,
+                UserHandle.getUserHandleForUid(uid))) {
+            cancelNotification(getCredentialPermissionNotificationId(account,
+                    AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+                    UserHandle.getUserHandleForUid(uid));
+        }
     }
 
     @Override
@@ -1722,6 +1851,21 @@
         } finally {
             Binder.restoreCallingIdentity(id);
         }
+
+        if (isChanged) {
+            synchronized (accounts.credentialsPermissionNotificationIds) {
+                for (Pair<Pair<Account, String>, Integer> key
+                        : accounts.credentialsPermissionNotificationIds.keySet()) {
+                    if (account.equals(key.first.first)
+                            && AccountManager.ACCOUNT_ACCESS_TOKEN.equals(key.first.second)) {
+                        final int uid = (Integer) key.second;
+                        mMessageHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
+                                account, uid, false));
+                    }
+                }
+            }
+        }
+
         return isChanged;
     }
 
@@ -2118,7 +2262,7 @@
 
         final int callingUid = getCallingUid();
         clearCallingIdentity();
-        if (callingUid != Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
             throw new SecurityException("can only call from system");
         }
         int userId = UserHandle.getUserId(callingUid);
@@ -2318,9 +2462,11 @@
                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
                             Intent intent = newGrantCredentialsPermissionIntent(
                                     account,
+                                    null,
                                     callerUid,
                                     new AccountAuthenticatorResponse(this),
-                                    authTokenType);
+                                    authTokenType,
+                                    true);
                             Bundle bundle = new Bundle();
                             bundle.putParcelable(AccountManager.KEY_INTENT, intent);
                             onResult(bundle);
@@ -2371,7 +2517,7 @@
                                     intent);
                             doNotification(mAccounts,
                                     account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
-                                    intent, accounts.userId);
+                                    intent, "android", accounts.userId);
                         }
                     }
                     super.onResult(result);
@@ -2402,7 +2548,7 @@
     }
 
     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
-            int userId) {
+            String packageName, int userId) {
         int uid = intent.getIntExtra(
                 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
         String authTokenType = intent.getStringExtra(
@@ -2430,20 +2576,23 @@
                         PendingIntent.FLAG_CANCEL_CURRENT, null, user))
                 .build();
         installNotification(getCredentialPermissionNotificationId(
-                account, authTokenType, uid), n, user);
+                account, authTokenType, uid), n, packageName, user.getIdentifier());
     }
 
-    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
-            AccountAuthenticatorResponse response, String authTokenType) {
+    private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
+            int uid, AccountAuthenticatorResponse response, String authTokenType,
+            boolean startInNewTask) {
 
         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
-        // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
-        // Since it was set in Eclair+ we can't change it without breaking apps using
-        // the intent from a non-Activity context.
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addCategory(
-                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
 
+        if (startInNewTask) {
+            // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
+            // Since it was set in Eclair+ we can't change it without breaking apps using
+            // the intent from a non-Activity context. This is the default behavior.
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
+                authTokenType, uid) + (packageName != null ? packageName : "")));
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
@@ -3294,6 +3443,123 @@
     }
 
     @Override
+    public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
+            @NonNull UserHandle userHandle) {
+        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+            throw new SecurityException("Can be called only by system UID");
+        }
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+
+        final int userId = userHandle.getIdentifier();
+
+        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);
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    private boolean checkUidPermission(String permission, int uid, String opPackageName) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = ActivityThread.getPackageManager();
+            if (pm.checkUidPermission(permission, uid) != PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+            final int opCode = AppOpsManager.permissionToOpCode(permission);
+            return (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
+                    opCode, uid, opPackageName) == AppOpsManager.MODE_ALLOWED);
+        } catch (RemoteException e) {
+            /* ignore - local call */
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return false;
+    }
+
+    @Override
+    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
+            @NonNull String packageName, @NonNull UserHandle userHandle) {
+        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+            throw new SecurityException("Can be called only by system UID");
+        }
+
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+
+        final int userId = userHandle.getIdentifier();
+
+        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
+
+        final int uid;
+        try {
+            uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException e) {
+            Slog.e(TAG, "Unknown package " + packageName);
+            return null;
+        }
+
+        Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return PendingIntent.getActivityAsUser(
+                    mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
+                            | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                    null, new UserHandle(userId)).getIntentSender();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private Intent newRequestAccountAccessIntent(Account account, String packageName,
+            int uid, RemoteCallback callback) {
+        return newGrantCredentialsPermissionIntent(account, packageName, uid,
+                new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
+            @Override
+            public void onResult(Bundle value) throws RemoteException {
+                handleAuthenticatorResponse(true);
+            }
+
+            @Override
+            public void onRequestContinued() {
+                /* ignore */
+            }
+
+            @Override
+            public void onError(int errorCode, String errorMessage) throws RemoteException {
+                handleAuthenticatorResponse(false);
+            }
+
+            private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
+                cancelNotification(getCredentialPermissionNotificationId(account,
+                        AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+                        UserHandle.getUserHandleForUid(uid));
+                if (callback != null) {
+                    Bundle result = new Bundle();
+                    result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
+                    callback.sendResult(result);
+                }
+            }
+        }), AccountManager.ACCOUNT_ACCESS_TOKEN, false);
+    }
+
+    @Override
     public boolean someUserHasAccount(@NonNull final Account account) {
         if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
             throw new SecurityException("Only system can check for accounts across users");
@@ -4933,7 +5199,7 @@
     }
 
     private void doNotification(UserAccounts accounts, Account account, CharSequence message,
-            Intent intent, int userId) {
+            Intent intent, String packageName, final int userId) {
         long identityToken = clearCallingIdentity();
         try {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -4943,12 +5209,12 @@
             if (intent.getComponent() != null &&
                     GrantCredentialsPermissionActivity.class.getName().equals(
                             intent.getComponent().getClassName())) {
-                createNoCredentialsPermissionNotification(account, intent, userId);
+                createNoCredentialsPermissionNotification(account, intent, packageName, userId);
             } else {
+                Context contextForUser = getContextForUser(new UserHandle(userId));
                 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
                 intent.addCategory(String.valueOf(notificationId));
-                UserHandle user = new UserHandle(userId);
-                Context contextForUser = getContextForUser(user);
+
                 final String notificationTitleFormat =
                         contextForUser.getText(R.string.notification_title).toString();
                 Notification n = new Notification.Builder(contextForUser)
@@ -4960,9 +5226,9 @@
                         .setContentText(message)
                         .setContentIntent(PendingIntent.getActivityAsUser(
                                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
-                                null, user))
+                                null, new UserHandle(userId)))
                         .build();
-                installNotification(notificationId, n, user);
+                installNotification(notificationId, n, packageName, userId);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -4970,18 +5236,40 @@
     }
 
     @VisibleForTesting
-    protected void installNotification(final int notificationId, final Notification n,
+    protected void installNotification(int notificationId, final Notification notification,
             UserHandle user) {
-        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                .notifyAsUser(null, notificationId, n, user);
+        installNotification(notificationId, notification, "android", user.getIdentifier());
+    }
+
+    private void installNotification(int notificationId, final Notification notification,
+            String packageName, int userId) {
+        final long token = clearCallingIdentity();
+        try {
+            INotificationManager notificationManager = NotificationManager.getService();
+            try {
+                notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
+                        notificationId, notification, new int[1], userId);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @VisibleForTesting
     protected void cancelNotification(int id, UserHandle user) {
+        cancelNotification(id, mContext.getPackageName(), user);
+    }
+
+    protected void cancelNotification(int id, String packageName, UserHandle user) {
         long identityToken = clearCallingIdentity();
         try {
-            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                .cancelAsUser(null, id, user);
+            INotificationManager service = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+            service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
+        } catch (RemoteException e) {
+            /* ignore - local call */
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -5042,18 +5330,40 @@
 
     private boolean permissionIsGranted(
             Account account, String authTokenType, int callerUid, int userId) {
-        final boolean isPrivileged = isPrivileged(callerUid);
-        final boolean fromAuthenticator = account != null
-                && isAccountManagedByCaller(account.type, callerUid, userId);
-        final boolean hasExplicitGrants = account != null
-                && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
-                    + callerUid + ", " + account
-                    + ": is authenticator? " + fromAuthenticator
-                    + ", has explicit permission? " + hasExplicitGrants);
+        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid is system");
+            }
+            return true;
         }
-        return fromAuthenticator || hasExplicitGrants || isPrivileged;
+
+        if (isPrivileged(callerUid)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid "
+                        + callerUid + " privileged");
+            }
+            return true;
+        }
+        if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid "
+                        + callerUid + " manages the account");
+            }
+            return true;
+        }
+        if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid "
+                        + callerUid + " user granted access");
+            }
+            return true;
+        }
+
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
+        }
+
+        return false;
     }
 
     private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
@@ -5137,16 +5447,26 @@
 
     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
             int callerUid) {
-        if (callerUid == Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
             return true;
         }
-        UserAccounts accounts = getUserAccountsForCaller();
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-            String[] args = { String.valueOf(callerUid), authTokenType,
-                    account.name, account.type};
-            final boolean permissionGranted =
-                    DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
+
+            final String query;
+            final String[] args;
+
+            if (authTokenType != null) {
+                query = COUNT_OF_MATCHING_GRANTS;
+                args = new String[] {String.valueOf(callerUid), authTokenType,
+                        account.name, account.type};
+            } else {
+                query = COUNT_OF_MATCHING_GRANTS_ANY_TOKEN;
+                args = new String[] {String.valueOf(callerUid), account.name,
+                        account.type};
+            }
+            final boolean permissionGranted = DatabaseUtils.longForQuery(db, query, args) != 0;
             if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
                 // TODO: Skip this check when running automated tests. Replace this
                 // with a more general solution.
@@ -5245,7 +5565,7 @@
             throws RemoteException {
         final int callingUid = getCallingUid();
 
-        if (callingUid != Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
             throw new SecurityException();
         }
 
@@ -5287,6 +5607,8 @@
             }
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
                     UserHandle.of(accounts.userId));
+
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
         }
     }
 
@@ -5604,4 +5926,45 @@
             }
         }
     }
+
+    private final class AccountManagerInternalImpl extends AccountManagerInternal {
+        @Override
+        public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
+                @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
+            if (account == null) {
+                Slog.w(TAG, "account cannot be null");
+                return;
+            }
+            if (packageName == null) {
+                Slog.w(TAG, "packageName cannot be null");
+                return;
+            }
+            if (userId < UserHandle.USER_SYSTEM) {
+                Slog.w(TAG, "user id must be concrete");
+                return;
+            }
+            if (callback == null) {
+                Slog.w(TAG, "callback cannot be null");
+                return;
+            }
+
+            if (hasAccountAccess(account, packageName, new UserHandle(userId))) {
+                Bundle result = new Bundle();
+                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+                callback.sendResult(result);
+                return;
+            }
+
+            final int uid;
+            try {
+                uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+            } catch (NameNotFoundException e) {
+                Slog.e(TAG, "Unknown package " + packageName);
+                return;
+            }
+
+            Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
+            doNotification(mUsers.get(userId), account, null, intent, packageName, userId);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9e601eb..aedf089 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1158,6 +1158,7 @@
      * For example, references to the commonly used services.
      */
     HashMap<String, IBinder> mAppBindArgs;
+    HashMap<String, IBinder> mIsolatedAppBindArgs;
 
     /**
      * Temporary to avoid allocations.  Protected by main lock.
@@ -2935,18 +2936,24 @@
      * lazily setup to make sure the services are running when they're asked for.
      */
     private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
+        // Isolated processes won't get this optimization, so that we don't
+        // violate the rules about which services they have access to.
+        if (isolated) {
+            if (mIsolatedAppBindArgs == null) {
+                mIsolatedAppBindArgs = new HashMap<>();
+                mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
+            }
+            return mIsolatedAppBindArgs;
+        }
+
         if (mAppBindArgs == null) {
             mAppBindArgs = new HashMap<>();
 
-            // Isolated processes won't get this optimization, so that we don't
-            // violate the rules about which services they have access to.
-            if (!isolated) {
-                // Setup the application init args
-                mAppBindArgs.put("package", ServiceManager.getService("package"));
-                mAppBindArgs.put("window", ServiceManager.getService("window"));
-                mAppBindArgs.put(Context.ALARM_SERVICE,
-                        ServiceManager.getService(Context.ALARM_SERVICE));
-            }
+            // Setup the application init args
+            mAppBindArgs.put("package", ServiceManager.getService("package"));
+            mAppBindArgs.put("window", ServiceManager.getService("window"));
+            mAppBindArgs.put(Context.ALARM_SERVICE,
+                    ServiceManager.getService(Context.ALARM_SERVICE));
         }
         return mAppBindArgs;
     }
@@ -13813,7 +13820,7 @@
                     try {
                         java.lang.Process logcat = new ProcessBuilder(
                                 "/system/bin/timeout", "-k", "15s", "10s",
-                                "/system/bin/logcat", "-v", "time", "-b", "events", "-b", "system",
+                                "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system",
                                 "-b", "main", "-b", "crash", "-t", String.valueOf(lines))
                                         .redirectErrorStream(true).start();
 
@@ -17770,6 +17777,7 @@
                 || Intent.ACTION_MEDIA_BUTTON.equals(action)
                 || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                 || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
+                || Intent.ACTION_MASTER_CLEAR.equals(action)
                 || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                 || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                 || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 5252446..6c61226 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -103,6 +103,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PowerManagerInternal;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -132,6 +133,9 @@
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
 
+    // TODO b/30204367 remove when the platform fully supports ephemeral applications
+    private static final boolean USE_DEFAULT_EPHEMERAL_LAUNCHER = false;
+
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mSupervisor;
     private ActivityStartInterceptor mInterceptor;
@@ -456,39 +460,13 @@
         // starts either the intent we resolved here [on install error] or the ephemeral
         // app [on install success].
         if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
-            // Create a pending intent to start the intent resolved here.
-            final IIntentSender failureTarget = mService.getIntentSenderLocked(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
-                    new String[]{ resolvedType },
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                            | PendingIntent.FLAG_IMMUTABLE, null);
-
-            // Create a pending intent to start the ephemeral application; force it to be
-            // directed to the ephemeral package.
-            ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
-            final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
-                    new String[]{ resolvedType },
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                            | PendingIntent.FLAG_IMMUTABLE, null);
-
-            int flags = intent.getFlags();
-            intent = new Intent();
-            intent.setFlags(flags
-                    | Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
-                    rInfo.ephemeralResolveInfo.getPackageName());
-            intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
-            intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
-
+            intent = buildEphemeralInstallerIntent(intent, ephemeralIntent,
+                    rInfo.ephemeralResolveInfo.getPackageName(), callingPackage, resolvedType,
+                    userId);
             resolvedType = null;
             callingUid = realCallingUid;
             callingPid = realCallingPid;
 
-            rInfo = rInfo.ephemeralInstaller;
             aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
         }
 
@@ -543,6 +521,60 @@
         return err;
     }
 
+    /**
+     * Builds and returns an intent to launch the ephemeral installer.
+     */
+    private Intent buildEphemeralInstallerIntent(Intent launchIntent, Intent origIntent,
+            String ephemeralPackage, String callingPackage, String resolvedType, int userId) {
+        final Intent nonEphemeralIntent = new Intent(origIntent);
+        nonEphemeralIntent.setFlags(nonEphemeralIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
+        // Intent that is launched if the ephemeral package couldn't be installed
+        // for any reason.
+        final IIntentSender failureIntentTarget = mService.getIntentSenderLocked(
+                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 1,
+                new Intent[]{ nonEphemeralIntent }, new String[]{ resolvedType },
+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);
+
+        final Intent ephemeralIntent;
+        if (USE_DEFAULT_EPHEMERAL_LAUNCHER) {
+            // Force the intent to be directed to the ephemeral package
+            ephemeralIntent = new Intent(origIntent);
+            ephemeralIntent.setPackage(ephemeralPackage);
+        } else {
+            // Success intent goes back to the installer
+            // TODO; do we need any extras for the installer?
+            ephemeralIntent = new Intent(launchIntent);
+            ephemeralIntent.setData(null);
+        }
+
+        // Intent that is eventually launched if the ephemeral package was
+        // installed successfully. This will actually be launched by a platform
+        // broadcast receiver.
+        final IIntentSender successIntentTarget = mService.getIntentSenderLocked(
+                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                Binder.getCallingUid(), userId, null /*token*/, null /*resultWho*/, 0,
+                new Intent[]{ ephemeralIntent }, new String[]{ resolvedType },
+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+                | PendingIntent.FLAG_IMMUTABLE, null /*bOptions*/);
+
+        // Finally build the actual intent to launch the ephemeral installer
+        int flags = launchIntent.getFlags();
+        final Intent intent = new Intent();
+        intent.setFlags(flags
+                | Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_CLEAR_TASK
+                | Intent.FLAG_ACTIVITY_NO_HISTORY
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, ephemeralPackage);
+        intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureIntentTarget));
+        intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(successIntentTarget));
+        // TODO: Remove when the platform has fully implemented ephemeral apps
+        intent.setData(origIntent.getData());
+        return intent;
+    }
+
     void postStartActivityUncheckedProcessing(
             ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
             ActivityStack targetStack) {
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7eff773..576f2b2 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -575,6 +575,8 @@
     boolean handleAppCrashLocked(ProcessRecord app, String reason,
             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
         long now = SystemClock.uptimeMillis();
+        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
 
         Long crashTime;
         Long crashTimePersistent;
@@ -612,7 +614,9 @@
                 // processes run critical code.
                 mService.removeProcessLocked(app, false, false, "crash");
                 mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
-                return false;
+                if (!showBackground) {
+                    return false;
+                }
             }
             mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } else {
@@ -705,7 +709,7 @@
             }
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
-            if (mService.canShowErrorDialogs() && !crashSilenced) {
+            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced) {
                 proc.crashDialog = new AppErrorDialog(mContext, mService, data);
             } else {
                 // The device is asleep, so just pretend that the user
@@ -942,7 +946,9 @@
                     null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                     null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
 
-            if (mService.canShowErrorDialogs()) {
+            boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+            if (mService.canShowErrorDialogs() || showBackground) {
                 d = new AppNotRespondingDialog(mService,
                         mContext, proc, (ActivityRecord)data.get("activity"),
                         msg.arg1 != 0);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 2467a90..9c08453 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -38,6 +38,7 @@
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.util.Objects;
 
 final class PendingIntentRecord extends IIntentSender.Stub {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
@@ -102,7 +103,7 @@
             if (requestResolvedType != null) {
                 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
             }
-            hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
+            hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0);
             hash = (ODD_PRIME_NUMBER*hash) + _t;
             hashCode = hash;
             //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
@@ -121,20 +122,14 @@
                 if (userId != other.userId){
                     return false;
                 }
-                if (!packageName.equals(other.packageName)) {
+                if (!Objects.equals(packageName, other.packageName)) {
                     return false;
                 }
                 if (activity != other.activity) {
                     return false;
                 }
-                if (who != other.who) {
-                    if (who != null) {
-                        if (!who.equals(other.who)) {
-                            return false;
-                        }
-                    } else if (other.who != null) {
-                        return false;
-                    }
+                if (!Objects.equals(who, other.who)) {
+                    return false;
                 }
                 if (requestCode != other.requestCode) {
                     return false;
@@ -148,14 +143,8 @@
                         return false;
                     }
                 }
-                if (requestResolvedType != other.requestResolvedType) {
-                    if (requestResolvedType != null) {
-                        if (!requestResolvedType.equals(other.requestResolvedType)) {
-                            return false;
-                        }
-                    } else if (other.requestResolvedType != null) {
-                        return false;
-                    }
+                if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
+                    return false;
                 }
                 if (flags != other.flags) {
                     return false;
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 48fecd5..43eb251 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -87,6 +87,8 @@
     private final RecentTasks mRecentTasks;
     private final SparseArray<SparseBooleanArray> mTaskIdsInFile = new SparseArray<>();
     private final File mTaskIdsDir;
+    // To lock file operations in TaskPersister
+    private final Object mIoLock = new Object();
 
     /**
      * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
@@ -195,52 +197,52 @@
             return mTaskIdsInFile.get(userId).clone();
         }
         final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
-        BufferedReader reader = null;
-        String line;
-        try {
-            reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
-            while ((line = reader.readLine()) != null) {
-                for (String taskIdString : line.split("\\s+")) {
-                    int id = Integer.parseInt(taskIdString);
-                    persistedTaskIds.put(id, true);
+        synchronized (mIoLock) {
+            BufferedReader reader = null;
+            String line;
+            try {
+                reader = new BufferedReader(new FileReader(getUserPersistedTaskIdsFile(userId)));
+                while ((line = reader.readLine()) != null) {
+                    for (String taskIdString : line.split("\\s+")) {
+                        int id = Integer.parseInt(taskIdString);
+                        persistedTaskIds.put(id, true);
+                    }
                 }
+            } catch (FileNotFoundException e) {
+                // File doesn't exist. Ignore.
+            } catch (Exception e) {
+                Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
+            } finally {
+                IoUtils.closeQuietly(reader);
             }
-        } catch (FileNotFoundException e) {
-            // File doesn't exist. Ignore.
-        } catch (Exception e) {
-            Slog.e(TAG, "Error while reading taskIds file for user " + userId, e);
-        } finally {
-            IoUtils.closeQuietly(reader);
         }
         mTaskIdsInFile.put(userId, persistedTaskIds);
         return persistedTaskIds.clone();
     }
 
+
     @VisibleForTesting
-    void maybeWritePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
+    void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
         if (userId < 0) {
             return;
         }
-        SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
-        if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIds)) {
-            return;
-        }
         final File persistedTaskIdsFile = getUserPersistedTaskIdsFile(userId);
-        BufferedWriter writer = null;
-        try {
-            writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
-            for (int i = 0; i < taskIds.size(); i++) {
-                if (taskIds.valueAt(i)) {
-                    writer.write(String.valueOf(taskIds.keyAt(i)));
-                    writer.newLine();
+        synchronized (mIoLock) {
+            BufferedWriter writer = null;
+            try {
+                writer = new BufferedWriter(new FileWriter(persistedTaskIdsFile));
+                for (int i = 0; i < taskIds.size(); i++) {
+                    if (taskIds.valueAt(i)) {
+                        writer.write(String.valueOf(taskIds.keyAt(i)));
+                        writer.newLine();
+                    }
                 }
+            } catch (Exception e) {
+                Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
+            } finally {
+                IoUtils.closeQuietly(writer);
             }
-        } catch (Exception e) {
-            Slog.e(TAG, "Error while writing taskIds file for user " + userId, e);
-        } finally {
-            IoUtils.closeQuietly(writer);
         }
-        mTaskIdsInFile.put(userId, taskIds.clone());
     }
 
     void unloadUserDataFromMemory(int userId) {
@@ -543,16 +545,23 @@
     }
 
     private void writeTaskIdsFiles() {
-        int candidateUserIds[];
+        SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
         synchronized (mService) {
-            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
-        }
-        SparseBooleanArray taskIdsToSave;
-        for (int userId : candidateUserIds) {
-            synchronized (mService) {
-                taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId).clone();
+            for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
+                SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId);
+                SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
+                if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
+                    continue;
+                } else {
+                    SparseBooleanArray taskIdsToSaveCopy = taskIdsToSave.clone();
+                    mTaskIdsInFile.put(userId, taskIdsToSaveCopy);
+                    changedTaskIdsPerUser.put(userId, taskIdsToSaveCopy);
+                }
             }
-            maybeWritePersistedTaskIdsForUser(taskIdsToSave, userId);
+        }
+        for (int i = 0; i < changedTaskIdsPerUser.size(); i++) {
+            writePersistedTaskIdsForUser(changedTaskIdsPerUser.valueAt(i),
+                    changedTaskIdsPerUser.keyAt(i));
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index 7525f30..c2c1a8c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -25,6 +25,7 @@
 import android.net.RouteInfo;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
+import android.net.util.NetdService;
 import android.os.INetworkManagementService;
 import android.os.ServiceSpecificException;
 import android.os.RemoteException;
@@ -193,7 +194,7 @@
 
     private void configureLocalDns(
             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
-        INetd netd = getNetdServiceOrNull();
+        final INetd netd = NetdService.getInstance();
         if (netd == null) {
             if (newDnses != null) newDnses.clear();
             Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
@@ -265,18 +266,6 @@
         return localRoutes;
     }
 
-    private INetd getNetdServiceOrNull() {
-        if (mNMService != null) {
-            try {
-                return mNMService.getNetdService();
-            } catch (RemoteException ignored) {
-                // This blocks until netd can be reached, but it can return
-                // null during a netd crash.
-            }
-        }
-        return null;
-    }
-
     // Given a prefix like 2001:db8::/64 return 2001:db8::1.
     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
         final byte[] dnsBytes = localPrefix.getRawAddress();
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 01b2393..12955f5 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -482,7 +482,6 @@
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
                 syncManager.scheduleSync(account, userId, uId, authority, extras,
-                        0 /* no delay */, 0 /* no delay */,
                         false /* onlyThoseWithUnkownSyncableState */);
             }
         } finally {
@@ -547,11 +546,8 @@
                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
                         flextime, extras);
             } else {
-                long beforeRuntimeMillis = (flextime) * 1000;
-                long runtimeMillis = runAtTime * 1000;
                 syncManager.scheduleSync(
                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
-                        beforeRuntimeMillis, runtimeMillis,
                         false /* onlyThoseWithUnknownSyncableState */);
             }
         } finally {
@@ -841,7 +837,7 @@
         try {
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
-                return syncManager.getIsSyncable(
+                return syncManager.computeSyncable(
                         account, userId, providerName);
             }
         } finally {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 39ddc3a..f739fa8 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -64,6 +65,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PowerManager;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -79,6 +81,7 @@
 import android.util.Pair;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerInternal;
 import com.google.android.collect.Lists;
@@ -133,6 +136,8 @@
 public class SyncManager {
     static final String TAG = "SyncManager";
 
+    private static final boolean DEBUG_ACCOUNT_ACCESS = false;
+
     /** Delay a sync due to local changes this long. In milliseconds */
     private static final long LOCAL_SYNC_DELAY;
 
@@ -194,6 +199,11 @@
     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
     private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
 
+
+    private static final int SYNC_OP_STATE_VALID = 0;
+    private static final int SYNC_OP_STATE_INVALID = 1;
+    private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
+
     private Context mContext;
 
     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -310,6 +320,10 @@
 
     private final UserManager mUserManager;
 
+    private final AccountManager mAccountManager;
+
+    private final AccountManagerInternal mAccountManagerInternal;
+
     private List<UserInfo> getAllUsers() {
         return mUserManager.getUsers();
     }
@@ -490,8 +504,6 @@
             @Override
             public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
                 scheduleSync(info.account, info.userId, reason, info.provider, extras,
-                        0 /* no flexMillis */,
-                        0 /* run immediately */,
                         false);
             }
         });
@@ -522,8 +534,7 @@
                 if (!removed) {
                     scheduleSync(null, UserHandle.USER_ALL,
                             SyncOperation.REASON_SERVICE_CHANGED,
-                            type.authority, null, 0 /* no delay */, 0 /* no delay */,
-                            false /* onlyThoseWithUnkownSyncableState */);
+                            type.authority, null, false /* onlyThoseWithUnkownSyncableState */);
                 }
             }
         }, mSyncHandler);
@@ -562,6 +573,9 @@
         }
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
+        mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
+
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                 BatteryStats.SERVICE_NAME));
 
@@ -655,7 +669,7 @@
         return mSyncStorageEngine;
     }
 
-    public int getIsSyncable(Account account, int userId, String providerName) {
+    private int getIsSyncable(Account account, int userId, String providerName) {
         int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
         UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
 
@@ -666,22 +680,22 @@
         RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
                 mSyncAdapters.getServiceInfo(
                         SyncAdapterType.newKey(providerName, account.type), userId);
-        if (syncAdapterInfo == null) return isSyncable;
+        if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
 
         PackageInfo pInfo = null;
         try {
             pInfo = AppGlobals.getPackageManager().getPackageInfo(
                     syncAdapterInfo.componentName.getPackageName(), 0, userId);
-            if (pInfo == null) return isSyncable;
+            if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
         } catch (RemoteException re) {
             // Shouldn't happen.
-            return isSyncable;
+            return AuthorityInfo.NOT_SYNCABLE;
         }
         if (pInfo.restrictedAccountType != null
                 && pInfo.restrictedAccountType.equals(account.type)) {
             return isSyncable;
         } else {
-            return 0;
+            return AuthorityInfo.NOT_SYNCABLE;
         }
     }
 
@@ -733,13 +747,10 @@
      * @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 beforeRuntimeMillis milliseconds before runtimeMillis that this sync can run.
-     * @param runtimeMillis maximum milliseconds in the future to wait before performing sync.
      * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
-            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
-            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+            String requestedAuthority, Bundle extras, boolean onlyThoseWithUnkownSyncableState) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -749,17 +760,27 @@
                     + requestedAuthority);
         }
 
-        AccountAndUser[] accounts;
-        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
-            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
+        AccountAndUser[] accounts = null;
+        if (requestedAccount != null) {
+            if (userId != UserHandle.USER_ALL) {
+                accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
+            } else {
+                for (AccountAndUser runningAccount : mRunningAccounts) {
+                    if (requestedAccount.equals(runningAccount.account)) {
+                        accounts = ArrayUtils.appendElement(AccountAndUser.class,
+                                accounts, runningAccount);
+                    }
+                }
+            }
         } else {
             accounts = mRunningAccounts;
-            if (accounts.length == 0) {
-                if (isLoggable) {
-                    Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
-                }
-                return;
+        }
+
+        if (ArrayUtils.isEmpty(accounts)) {
+            if (isLoggable) {
+                Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
             }
+            return;
         }
 
         final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
@@ -808,29 +829,41 @@
             }
 
             for (String authority : syncableAuthorities) {
-                int isSyncable = getIsSyncable(account.account, account.userId,
-                        authority);
+                int isSyncable = computeSyncable(account.account, account.userId, authority);
+
                 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
                     continue;
                 }
-                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
-                syncAdapterInfo = mSyncAdapters.getServiceInfo(
-                        SyncAdapterType.newKey(authority, account.account.type), account.userId);
+
+                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+                        mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
+                                account.account.type), account.userId);
                 if (syncAdapterInfo == null) {
                     continue;
                 }
+
                 final int owningUid = syncAdapterInfo.uid;
-                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
-                try {
-                    if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
-                            owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
-                        Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
-                                + syncAdapterInfo.componentName
-                                + " -- package not allowed to start");
-                        continue;
+
+                if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
+                    if (isLoggable) {
+                        Slog.v(TAG, "    Not scheduling sync operation: "
+                                + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
                     }
-                } catch (RemoteException e) {
+                    Bundle finalExtras = new Bundle(extras);
+                    mAccountManagerInternal.requestAccountAccess(account.account,
+                            syncAdapterInfo.componentName.getPackageName(),
+                            UserHandle.getUserId(owningUid),
+                            new RemoteCallback((Bundle result) -> {
+                                if (result != null
+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+                                    scheduleSync(account.account, userId, reason, authority,
+                                            finalExtras, onlyThoseWithUnkownSyncableState);
+                                }
+                            }
+                        ));
+                    continue;
                 }
+
                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
                 if (isSyncable < 0 && isAlwaysSyncable) {
@@ -838,6 +871,7 @@
                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
                     isSyncable = AuthorityInfo.SYNCABLE;
                 }
+
                 if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
                     continue;
                 }
@@ -863,6 +897,9 @@
                                 account.account, authority, account.userId);
                 long delayUntil =
                         mSyncStorageEngine.getDelayUntilTime(info);
+
+                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
+
                 if (isSyncable < 0) {
                     // Initialisation sync.
                     Bundle newExtras = new Bundle();
@@ -887,8 +924,6 @@
                     if (isLoggable) {
                         Slog.v(TAG, "scheduleSync:"
                                 + " delay until " + delayUntil
-                                + " run by " + runtimeMillis
-                                + " flexMillis " + beforeRuntimeMillis
                                 + ", source " + source
                                 + ", account " + account
                                 + ", authority " + authority
@@ -904,6 +939,56 @@
         }
     }
 
+    public int computeSyncable(Account account, int userId, String authority) {
+        final int status = getIsSyncable(account, userId, authority);
+        if (status == AuthorityInfo.NOT_SYNCABLE) {
+            return AuthorityInfo.NOT_SYNCABLE;
+        }
+        final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
+        final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+                mSyncAdapters.getServiceInfo(type, userId);
+        if (syncAdapterInfo == null) {
+            return AuthorityInfo.NOT_SYNCABLE;
+        }
+        final int owningUid = syncAdapterInfo.uid;
+        final String owningPackage = syncAdapterInfo.componentName.getPackageName();
+        try {
+            if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
+                    owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
+                Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
+                        + syncAdapterInfo.componentName
+                        + " -- package not allowed to start");
+                return AuthorityInfo.NOT_SYNCABLE;
+            }
+        } catch (RemoteException e) {
+            /* ignore - local call */
+        }
+        if (!canAccessAccount(account, owningPackage, owningUid)) {
+            Log.w(TAG, "Access to " + account + " denied for package "
+                    + owningPackage + " in UID " + syncAdapterInfo.uid);
+            return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
+        }
+
+        return status;
+    }
+
+    private boolean canAccessAccount(Account account, String packageName, int uid) {
+        if (mAccountManager.hasAccountAccess(account, packageName,
+                UserHandle.getUserHandleForUid(uid))) {
+            return true;
+        }
+        // We relax the account access rule to also include the system apps as
+        // they are trusted and we want to minimize the cases where the user
+        // involvement is required to grant access to the synced account.
+        try {
+            mContext.getPackageManager().getApplicationInfoAsUser(packageName,
+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
+            return true;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
     private void removeSyncsForAuthority(EndPoint info) {
         verifyJobScheduler();
         List<SyncOperation> ops = getAllPendingSyncs();
@@ -960,8 +1045,6 @@
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
         scheduleSync(account, userId, reason, authority, extras,
-                LOCAL_SYNC_DELAY /* earliest run time */,
-                2 * LOCAL_SYNC_DELAY /* latest sync time. */,
                 false /* onlyThoseWithUnkownSyncableState */);
     }
 
@@ -1421,7 +1504,6 @@
                 mContext.getOpPackageName());
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
-                    0 /* no delay */, 0 /* No flexMillis */,
                     true /* onlyThoseWithUnknownSyncableState */);
         }
     }
@@ -2530,13 +2612,18 @@
                 }
             }
 
-            if (isOperationValid(op)) {
-                if (!dispatchSyncOperation(op)) {
+            final int syncOpState = computeSyncOpState(op);
+            switch (syncOpState) {
+                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
+                case SYNC_OP_STATE_INVALID: {
                     mSyncJobService.callJobFinished(op.jobId, false);
-                }
-            } else {
+                } return;
+            }
+
+            if (!dispatchSyncOperation(op)) {
                 mSyncJobService.callJobFinished(op.jobId, false);
             }
+
             setAuthorityPendingState(op.target);
         }
 
@@ -2596,8 +2683,7 @@
 
             if (syncTargets != null) {
                 scheduleSync(syncTargets.account, syncTargets.userId,
-                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, 0, 0,
-                        true);
+                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, true);
             }
         }
 
@@ -2665,6 +2751,26 @@
                     SyncStorageEngine.SOURCE_PERIODIC, extras,
                     syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
                     pollFrequencyMillis, flexMillis);
+
+            final int syncOpState = computeSyncOpState(op);
+            switch (syncOpState) {
+                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
+                    mAccountManagerInternal.requestAccountAccess(op.target.account,
+                            op.owningPackage, UserHandle.getUserId(op.owningUid),
+                            new RemoteCallback((Bundle result) -> {
+                                if (result != null
+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+                                    updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
+                                }
+                            }
+                        ));
+                } return;
+
+                case SYNC_OP_STATE_INVALID: {
+                    return;
+                }
+            }
+
             scheduleSyncOperationH(op);
             mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
         }
@@ -2725,29 +2831,38 @@
         /**
          * Determine if a sync is no longer valid and should be dropped.
          */
-        private boolean isOperationValid(SyncOperation op) {
+        private int computeSyncOpState(SyncOperation op) {
             final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
             int state;
             final EndPoint target = op.target;
-            boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId);
+
             // Drop the sync if the account of this operation no longer exists.
             AccountAndUser[] accounts = mRunningAccounts;
             if (!containsAccountAndUser(accounts, target.account, target.userId)) {
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: account doesn't exist.");
                 }
-                return false;
+                return SYNC_OP_STATE_INVALID;
             }
             // Drop this sync request if it isn't syncable.
-            state = getIsSyncable(target.account, target.userId, target.provider);
-            if (state == 0) {
+            state = computeSyncable(target.account, target.userId, target.provider);
+            if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
                 if (isLoggable) {
-                    Slog.v(TAG, "    Dropping sync operation: isSyncable == 0.");
+                    Slog.v(TAG, "    Dropping sync operation: "
+                            + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
                 }
-                return false;
+                return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
             }
-            syncEnabled = syncEnabled && mSyncStorageEngine.getSyncAutomatically(
-                    target.account, target.userId, target.provider);
+            if (state == AuthorityInfo.NOT_SYNCABLE) {
+                if (isLoggable) {
+                    Slog.v(TAG, "    Dropping sync operation: isSyncable == NOT_SYNCABLE");
+                }
+                return SYNC_OP_STATE_INVALID;
+            }
+
+            final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
+                    && mSyncStorageEngine.getSyncAutomatically(target.account,
+                            target.userId, target.provider);
 
             // We ignore system settings that specify the sync is invalid if:
             // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
@@ -2760,9 +2875,9 @@
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: disallowed by settings/network.");
                 }
-                return false;
+                return SYNC_OP_STATE_INVALID;
             }
-            return true;
+            return SYNC_OP_STATE_VALID;
         }
 
         private boolean dispatchSyncOperation(SyncOperation op) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index bc3fc6a..64849aa 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -234,6 +234,12 @@
          */
         public static final int SYNCABLE_NOT_INITIALIZED = 2;
 
+        /**
+         * The adapter is syncable but does not have access to the synced account and needs a
+         * user access approval.
+         */
+        public static final int SYNCABLE_NO_ACCOUNT_ACCESS = 3;
+
         final EndPoint target;
         final int ident;
         boolean enabled;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 0abd2e7..45a9644 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1402,6 +1402,9 @@
                 throw new IllegalArgumentException("width, height, and densityDpi must be "
                         + "greater than 0");
             }
+            if (surface.isSingleBuffered()) {
+                throw new IllegalArgumentException("Surface can't be single-buffered");
+            }
 
             if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
                 flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 07fa2ce..e7fd3d8 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -182,6 +182,8 @@
     }
 
     private void setUp() {
+        Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
+
         // Create a new controller for the current user and start listening for changes.
         mController = new NightDisplayController(getContext(), mCurrentUser);
         mController.setListener(this);
@@ -196,6 +198,8 @@
     }
 
     private void tearDown() {
+        Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
+
         if (mController != null) {
             mController.setListener(null);
             mController = null;
@@ -273,6 +277,8 @@
 
     @Override
     public void onAutoModeChanged(int autoMode) {
+        Slog.d(TAG, "onAutoModeChanged: autoMode=" + autoMode);
+
         if (mAutoMode != null) {
             mAutoMode.onStop();
             mAutoMode = null;
@@ -291,6 +297,8 @@
 
     @Override
     public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+        Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
+
         if (mAutoMode != null) {
             mAutoMode.onCustomStartTimeChanged(startTime);
         }
@@ -298,6 +306,8 @@
 
     @Override
     public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+        Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
+
         if (mAutoMode != null) {
             mAutoMode.onCustomEndTimeChanged(endTime);
         }
@@ -419,7 +429,7 @@
 
         @Override
         public void onAlarm() {
-            if (DEBUG) Slog.d(TAG, "onAlarm");
+            Slog.d(TAG, "onAlarm");
             updateActivated();
         }
     }
@@ -477,7 +487,8 @@
 
         @Override
         public void onTwilightStateChanged(@Nullable TwilightState state) {
-            if (DEBUG) Slog.d(TAG, "onTwilightStateChanged");
+            Slog.d(TAG, "onTwilightStateChanged: isNight="
+                    + (state == null ? null : state.isNight()));
             updateActivated(state);
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 777eee8..697186e 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -78,6 +78,8 @@
 public class MediaSessionService extends SystemService implements Monitor {
     private static final String TAG = "MediaSessionService";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    // Leave log for media key event always.
+    private static final boolean DEBUG_MEDIA_KEY_EVENT = DEBUG || true;
 
     private static final int WAKELOCK_TIMEOUT = 5000;
 
@@ -302,7 +304,7 @@
      */
     private void destroySessionLocked(MediaSessionRecord session) {
         if (DEBUG) {
-            Log.d(TAG, "Destroying session : " + session.toString());
+            Log.d(TAG, "Destroying " + session);
         }
         int userId = session.getUserId();
         UserRecord user = mUserRecords.get(userId);
@@ -408,7 +410,7 @@
                     if (component != null) {
                         if (compName.equals(component)) {
                             if (DEBUG) {
-                                Log.d(TAG, "ok to get sessions: " + component +
+                                Log.d(TAG, "ok to get sessions. " + component +
                                         " is authorized notification listener");
                             }
                             return true;
@@ -417,7 +419,7 @@
                 }
             }
             if (DEBUG) {
-                Log.d(TAG, "not ok to get sessions, " + compName +
+                Log.d(TAG, "not ok to get sessions. " + compName +
                         " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId);
             }
         }
@@ -462,7 +464,7 @@
         mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
 
         if (DEBUG) {
-            Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
+            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
         }
         return session;
     }
@@ -881,17 +883,16 @@
 
         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags,
                 MediaSessionRecord session) {
-            if (DEBUG) {
-                String description = session == null ? null : session.toString();
-                Log.d(TAG, "Adjusting session " + description + " by " + direction + ". flags="
-                        + flags + ", suggestedStream=" + suggestedStream);
-
-            }
             boolean preferSuggestedStream = false;
             if (isValidLocalStreamType(suggestedStream)
                     && AudioSystem.isStreamActive(suggestedStream, 0)) {
                 preferSuggestedStream = true;
             }
+            if (DEBUG) {
+                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
+                        + flags + ", suggestedStream=" + suggestedStream
+                        + ", preferSuggestedStream=" + preferSuggestedStream);
+            }
             if (session == null || preferSuggestedStream) {
                 if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
                         && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
@@ -946,8 +947,8 @@
         private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
                 MediaSessionRecord session) {
             if (session != null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Sending media key to " + session.toString());
+                if (DEBUG_MEDIA_KEY_EVENT) {
+                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
                 }
                 if (needWakeLock) {
                     mKeyEventReceiver.aquireWakeLockLocked();
@@ -966,11 +967,6 @@
                             && user.mRestoredMediaButtonReceiver == null) {
                         continue;
                     }
-                    if (DEBUG) {
-                        Log.d(TAG, "Sending media key to last known PendingIntent "
-                                + user.mLastMediaButtonReceiver + " or restored Intent "
-                                + user.mRestoredMediaButtonReceiver);
-                    }
                     if (needWakeLock) {
                         mKeyEventReceiver.aquireWakeLockLocked();
                     }
@@ -979,10 +975,19 @@
                     mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
                     try {
                         if (user.mLastMediaButtonReceiver != null) {
+                            if (DEBUG_MEDIA_KEY_EVENT) {
+                                Log.d(TAG, "Sending " + keyEvent
+                                        + " to the last known pendingIntent "
+                                        + user.mLastMediaButtonReceiver);
+                            }
                             user.mLastMediaButtonReceiver.send(getContext(),
                                     needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                                     mediaButtonIntent, mKeyEventReceiver, mHandler);
                         } else {
+                            if (DEBUG_MEDIA_KEY_EVENT) {
+                                Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+                                        + user.mRestoredMediaButtonReceiver);
+                            }
                             mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
                             getContext().sendBroadcastAsUser(mediaButtonIntent,
                                     UserHandle.of(userId));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6a56fa6..d25abbf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -870,13 +870,8 @@
                 IntentSender statusReceiver, int userId) {
         final int callingUid = Binder.getCallingUid();
         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
-        boolean allowSilentUninstall = true;
         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
             mAppOps.checkPackage(callingUid, callerPackageName);
-            final String installerPackageName = mPm.getInstallerPackageName(packageName);
-            allowSilentUninstall = mPm.isOrphaned(packageName) ||
-                    (installerPackageName != null
-                            && installerPackageName.equals(callerPackageName));
         }
 
         // Check whether the caller is device owner, in which case we do it silently.
@@ -887,8 +882,8 @@
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                 statusReceiver, packageName, isDeviceOwner, userId);
-        if (allowSilentUninstall && mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
+                    == PackageManager.PERMISSION_GRANTED) {
             // Sweet, call straight through!
             mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
         } else if (isDeviceOwner) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6cdc40f..5831284 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -109,6 +109,7 @@
     final int installerUid;
     final SessionParams params;
     final long createdMillis;
+    final int defaultContainerGid;
 
     /** Staging location where client data is written. */
     final File stageDir;
@@ -199,13 +200,19 @@
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
+            // Cache package manager data without the lock held
+            final PackageInfo pkgInfo = mPm.getPackageInfo(
+                    params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
+            final ApplicationInfo appInfo = mPm.getApplicationInfo(
+                    params.appPackageName, 0, userId);
+
             synchronized (mLock) {
                 if (msg.obj != null) {
                     mRemoteObserver = (IPackageInstallObserver2) msg.obj;
                 }
 
                 try {
-                    commitLocked();
+                    commitLocked(pkgInfo, appInfo);
                 } catch (PackageManagerException e) {
                     final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                     Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
@@ -264,6 +271,9 @@
         } else {
             mPermissionsAccepted = false;
         }
+        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
+                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+        defaultContainerGid = UserHandle.getSharedAppGid(uid);
     }
 
     public SessionInfo generateInfo() {
@@ -520,7 +530,8 @@
         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
     }
 
-    private void commitLocked() throws PackageManagerException {
+    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
+            throws PackageManagerException {
         if (mDestroyed) {
             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
         }
@@ -538,7 +549,7 @@
         // Verify that stage looks sane with respect to existing application.
         // This currently only ensures packageName, versionCode, and certificate
         // consistency.
-        validateInstallLocked();
+        validateInstallLocked(pkgInfo, appInfo);
 
         Preconditions.checkNotNull(mPackageName);
         Preconditions.checkNotNull(mSignatures);
@@ -650,7 +661,8 @@
      * Note that upgrade compatibility is still performed by
      * {@link PackageManagerService}.
      */
-    private void validateInstallLocked() throws PackageManagerException {
+    private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
+            throws PackageManagerException {
         mPackageName = null;
         mVersionCode = -1;
         mSignatures = null;
@@ -729,10 +741,8 @@
 
         if (removeSplitList.size() > 0) {
             // validate split names marked for removal
-            final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
-            final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
             for (String splitName : removeSplitList) {
-                if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
+                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                             "Split not found: " + splitName);
                 }
@@ -740,11 +750,11 @@
 
             // ensure we've got appropriate package name, version code and signatures
             if (mPackageName == null) {
-                mPackageName = pkg.packageName;
-                mVersionCode = pkg.versionCode;
+                mPackageName = pkgInfo.packageName;
+                mVersionCode = pkgInfo.versionCode;
             }
             if (mSignatures == null) {
-                mSignatures = pkg.signatures;
+                mSignatures = pkgInfo.signatures;
             }
         }
 
@@ -757,8 +767,7 @@
 
         } else {
             // Partial installs must be consistent with existing install
-            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
-            if (app == null) {
+            if (appInfo == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Missing existing base package for " + mPackageName);
             }
@@ -766,8 +775,8 @@
             final PackageLite existing;
             final ApkLite existingBase;
             try {
-                existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
-                existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
+                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
+                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
                         PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
@@ -777,7 +786,7 @@
 
             // Inherit base if not overridden
             if (mResolvedBaseFile == null) {
-                mResolvedBaseFile = new File(app.getBaseCodePath());
+                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 mResolvedInheritedFiles.add(mResolvedBaseFile);
             }
 
@@ -794,7 +803,7 @@
             }
 
             // Inherit compiled oat directory.
-            final File packageInstallDir = (new File(app.getBaseCodePath())).getParentFile();
+            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
             mInheritedFilesBase = packageInstallDir;
             final File oatDir = new File(packageInstallDir, "oat");
             if (oatDir.exists()) {
@@ -822,7 +831,8 @@
         }
     }
 
-    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
+    private void assertApkConsistent(String tag, ApkLite apk)
+            throws PackageManagerException {
         if (!mPackageName.equals(apk.packageName)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
                     + apk.packageName + " inconsistent with " + mPackageName);
@@ -1035,10 +1045,7 @@
                     "Failed to finalize container " + cid);
         }
 
-        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
-        final int gid = UserHandle.getSharedAppGid(uid);
-        if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
+        if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
                     "Failed to fix permissions on container " + cid);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f326555..f84356b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -177,6 +177,7 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.PatternMatcher;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -196,6 +197,7 @@
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.system.ErrnoException;
@@ -363,6 +365,7 @@
 
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
+    // STOPSHIP; b/30256615
     private static final boolean DISABLE_EPHEMERAL_APPS = !Build.IS_DEBUGGABLE;
 
     private static final int RADIO_UID = Process.PHONE_UID;
@@ -531,6 +534,7 @@
     final String[] mSeparateProcesses;
     final boolean mIsUpgrade;
     final boolean mIsPreNUpgrade;
+    final boolean mIsPreNMR1Upgrade;
 
     /** The location for ASEC container files on internal storage. */
     final String mAsecInternalPath;
@@ -2238,6 +2242,8 @@
             // as there is no profiling data available.
             mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
 
+            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
+
             // save off the names of pre-existing system packages prior to scanning; we don't
             // want to automatically grant runtime permissions for new system apps
             if (mPromoteSystemApps) {
@@ -4722,20 +4728,6 @@
 
             final ResolveInfo bestChoice =
                     chooseBestActivity(intent, resolvedType, flags, query, userId);
-
-            if (isEphemeralAllowed(intent, query, userId)) {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
-                final EphemeralResolveInfo ai =
-                        getEphemeralResolveInfo(intent, resolvedType, userId);
-                if (ai != null) {
-                    if (DEBUG_EPHEMERAL) {
-                        Slog.v(TAG, "Returning an EphemeralResolveInfo");
-                    }
-                    bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
-                    bestChoice.ephemeralResolveInfo = ai;
-                }
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
             return bestChoice;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -4776,11 +4768,23 @@
                 false, false, false, userId);
     }
 
+    private boolean isEphemeralDisabled() {
+        // ephemeral apps have been disabled across the board
+        if (DISABLE_EPHEMERAL_APPS) {
+            return true;
+        }
+        // system isn't up yet; can't read settings, so, assume no ephemeral apps
+        if (!mSystemReady) {
+            return true;
+        }
+        return Secure.getInt(mContext.getContentResolver(), Secure.WEB_ACTION_ENABLED, 1) == 0;
+    }
 
     private boolean isEphemeralAllowed(
-            Intent intent, List<ResolveInfo> resolvedActivites, int userId) {
+            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
+            boolean skipPackageCheck) {
         // Short circuit and return early if possible.
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return false;
         }
         final int callingUser = UserHandle.getCallingUserId();
@@ -4793,18 +4797,21 @@
         if (intent.getComponent() != null) {
             return false;
         }
-        if (intent.getPackage() != null) {
+        if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
+            return false;
+        }
+        if (!skipPackageCheck && intent.getPackage() != null) {
             return false;
         }
         final boolean isWebUri = hasWebURI(intent);
-        if (!isWebUri) {
+        if (!isWebUri || intent.getData().getHost() == null) {
             return false;
         }
         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
         synchronized (mPackages) {
-            final int count = resolvedActivites.size();
+            final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
             for (int n = 0; n < count; n++) {
-                ResolveInfo info = resolvedActivites.get(n);
+                ResolveInfo info = resolvedActivities.get(n);
                 String packageName = info.activityInfo.packageName;
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null) {
@@ -4826,19 +4833,19 @@
         return true;
     }
 
-    private EphemeralResolveInfo getEphemeralResolveInfo(Intent intent, String resolvedType,
-            int userId) {
-        final int ephemeralPrefixMask = Global.getInt(mContext.getContentResolver(),
+    private static EphemeralResolveInfo getEphemeralResolveInfo(
+            Context context, EphemeralResolverConnection resolverConnection, Intent intent,
+            String resolvedType, int userId, String packageName) {
+        final int ephemeralPrefixMask = Global.getInt(context.getContentResolver(),
                 Global.EPHEMERAL_HASH_PREFIX_MASK, DEFAULT_EPHEMERAL_HASH_PREFIX_MASK);
-        final int ephemeralPrefixCount = Global.getInt(mContext.getContentResolver(),
+        final int ephemeralPrefixCount = Global.getInt(context.getContentResolver(),
                 Global.EPHEMERAL_HASH_PREFIX_COUNT, DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT);
         final EphemeralDigest digest = new EphemeralDigest(intent.getData(), ephemeralPrefixMask,
                 ephemeralPrefixCount);
         final int[] shaPrefix = digest.getDigestPrefix();
         final byte[][] digestBytes = digest.getDigestBytes();
         final List<EphemeralResolveInfo> ephemeralResolveInfoList =
-                mEphemeralResolverConnection.getEphemeralResolveInfoList(
-                        shaPrefix, ephemeralPrefixMask);
+                resolverConnection.getEphemeralResolveInfoList(shaPrefix, ephemeralPrefixMask);
         if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
             // No hash prefix match; there are no ephemeral apps for this domain.
             return null;
@@ -4855,6 +4862,10 @@
                 if (filters.isEmpty()) {
                     continue;
                 }
+                if (packageName != null
+                        && !packageName.equals(ephemeralApplication.getPackageName())) {
+                    continue;
+                }
                 // We have a domain match; resolve the filters to see if anything matches.
                 final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
                 for (int j = filters.size() - 1; j >= 0; --j) {
@@ -5258,8 +5269,12 @@
         }
 
         // reader
+        boolean sortResult = false;
+        boolean addEphemeral = false;
+        boolean matchEphemeralPackage = false;
+        List<ResolveInfo> result;
+        final String pkgName = intent.getPackage();
         synchronized (mPackages) {
-            final String pkgName = intent.getPackage();
             if (pkgName == null) {
                 List<CrossProfileIntentFilter> matchingFilters =
                         getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
@@ -5267,15 +5282,16 @@
                 ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                         resolvedType, flags, userId);
                 if (xpResolveInfo != null) {
-                    List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
-                    result.add(xpResolveInfo);
-                    return filterIfNotSystemUser(result, userId);
+                    List<ResolveInfo> xpResult = new ArrayList<ResolveInfo>(1);
+                    xpResult.add(xpResolveInfo);
+                    return filterIfNotSystemUser(xpResult, userId);
                 }
 
                 // Check for results in the current profile.
-                List<ResolveInfo> result = mActivities.queryIntent(
-                        intent, resolvedType, flags, userId);
-                result = filterIfNotSystemUser(result, userId);
+                result = filterIfNotSystemUser(mActivities.queryIntent(
+                        intent, resolvedType, flags, userId), userId);
+                addEphemeral =
+                        isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
 
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
@@ -5287,7 +5303,7 @@
                             Collections.singletonList(xpResolveInfo), userId).size() > 0;
                     if (isVisibleToUser) {
                         result.add(xpResolveInfo);
-                        Collections.sort(result, mResolvePrioritySorter);
+                        sortResult = true;
                     }
                 }
                 if (hasWebURI(intent)) {
@@ -5303,28 +5319,61 @@
                             // in the result.
                             result.remove(xpResolveInfo);
                         }
-                        if (result.size() == 0) {
+                        if (result.size() == 0 && !addEphemeral) {
                             result.add(xpDomainInfo.resolveInfo);
                             return result;
                         }
-                    } else if (result.size() <= 1) {
-                        return result;
                     }
-                    result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
-                            xpDomainInfo, userId);
-                    Collections.sort(result, mResolvePrioritySorter);
+                    if (result.size() > 1 || addEphemeral) {
+                        result = filterCandidatesWithDomainPreferredActivitiesLPr(
+                                intent, flags, result, xpDomainInfo, userId);
+                        sortResult = true;
+                    }
                 }
-                return result;
+            } else {
+                final PackageParser.Package pkg = mPackages.get(pkgName);
+                if (pkg != null) {
+                    result = filterIfNotSystemUser(
+                            mActivities.queryIntentForPackage(
+                                    intent, resolvedType, flags, pkg.activities, userId),
+                            userId);
+                } else {
+                    // the caller wants to resolve for a particular package; however, there
+                    // were no installed results, so, try to find an ephemeral result
+                    addEphemeral = isEphemeralAllowed(
+                            intent, null /*result*/, userId, true /*skipPackageCheck*/);
+                    matchEphemeralPackage = true;
+                    result = new ArrayList<ResolveInfo>();
+                }
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
-            if (pkg != null) {
-                return filterIfNotSystemUser(
-                        mActivities.queryIntentForPackage(
-                                intent, resolvedType, flags, pkg.activities, userId),
-                        userId);
-            }
-            return new ArrayList<ResolveInfo>();
         }
+        if (addEphemeral) {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
+            final EphemeralResolveInfo ai = getEphemeralResolveInfo(
+                    mContext, mEphemeralResolverConnection, intent, resolvedType, userId,
+                    matchEphemeralPackage ? pkgName : null);
+            if (ai != null) {
+                if (DEBUG_EPHEMERAL) {
+                    Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
+                }
+                final ResolveInfo ephemeralInstaller = new ResolveInfo(mEphemeralInstallerInfo);
+                ephemeralInstaller.ephemeralResolveInfo = ai;
+                // make sure this resolver is the default
+                ephemeralInstaller.isDefault = true;
+                ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+                        | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+                // add a non-generic filter
+                ephemeralInstaller.filter = new IntentFilter(intent.getAction());
+                ephemeralInstaller.filter.addDataPath(
+                        intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+                result.add(ephemeralInstaller);
+            }
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+        if (sortResult) {
+            Collections.sort(result, mResolvePrioritySorter);
+        }
+        return result;
     }
 
     private static class CrossProfileDomainInfo {
@@ -6204,7 +6253,7 @@
 
     @Override
     public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return null;
         }
 
@@ -6228,7 +6277,7 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "isEphemeral");
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return false;
         }
 
@@ -6246,7 +6295,7 @@
 
     @Override
     public byte[] getEphemeralApplicationCookie(String packageName, int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return null;
         }
 
@@ -6264,7 +6313,7 @@
 
     @Override
     public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return true;
         }
 
@@ -6282,7 +6331,7 @@
 
     @Override
     public Bitmap getEphemeralApplicationIcon(String packageName, int userId) {
-        if (DISABLE_EPHEMERAL_APPS) {
+        if (isEphemeralDisabled()) {
             return null;
         }
 
@@ -6612,9 +6661,13 @@
 
     private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
             final int policyFlags) throws PackageManagerException {
+        // When upgrading from pre-N MR1, verify the package time stamp using the package
+        // directory and not the APK file.
+        final long lastModifiedTime = mIsPreNMR1Upgrade
+                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg, srcFile);
         if (ps != null
                 && ps.codePath.equals(srcFile)
-                && ps.timeStamp == getLastModifiedTime(pkg, srcFile)
+                && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(pkg)
                 && !isRecoverSignatureUpdateNeeded(pkg)) {
             long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
@@ -6636,7 +6689,7 @@
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+            Slog.i(TAG, srcFile.toString() + " changed; collecting certs");
         }
 
         try {
@@ -8366,6 +8419,10 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
         }
 
+        if (isSystemApp(pkg)) {
+            pkgSetting.isOrphaned = true;
+        }
+
         ArrayList<PackageParser.Package> clientLibPkgs = null;
 
         if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
@@ -8649,7 +8706,9 @@
             for (i=0; i<N; i++) {
                 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
                 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
-                if (cur == null) {
+                final String curPackageName = cur == null ? null : cur.info.packageName;
+                final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+                if (cur == null || isPackageUpdate) {
                     mPermissionGroups.put(pg.info.name, pg);
                     if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
                         if (r == null) {
@@ -8657,6 +8716,9 @@
                         } else {
                             r.append(' ');
                         }
+                        if (isPackageUpdate) {
+                            r.append("UPD:");
+                        }
                         r.append(pg.info.name);
                     }
                 } else {
@@ -9189,15 +9251,17 @@
         mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
         mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
         mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
-                ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+        mEphemeralInstallerActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
+                | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
         mEphemeralInstallerActivity.theme = 0;
         mEphemeralInstallerActivity.exported = true;
         mEphemeralInstallerActivity.enabled = true;
         mEphemeralInstallerInfo.activityInfo = mEphemeralInstallerActivity;
         mEphemeralInstallerInfo.priority = 0;
-        mEphemeralInstallerInfo.preferredOrder = 0;
-        mEphemeralInstallerInfo.match = 0;
+        mEphemeralInstallerInfo.preferredOrder = 1;
+        mEphemeralInstallerInfo.isDefault = true;
+        mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+                | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
 
         if (DEBUG_EPHEMERAL) {
             Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent);
@@ -15310,6 +15374,19 @@
         Preconditions.checkNotNull(packageName);
         Preconditions.checkNotNull(observer);
         final int uid = Binder.getCallingUid();
+        if (uid != Process.SHELL_UID && uid != Process.ROOT_UID && uid != Process.SYSTEM_UID
+                && uid != getPackageUid(mRequiredInstallerPackage, 0, UserHandle.getUserId(uid))
+                && !isOrphaned(packageName)
+                && !isCallerSameAsInstaller(uid, packageName)) {
+            try {
+                final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+                intent.setData(Uri.fromParts("package", packageName, null));
+                intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
+                observer.onUserActionRequired(intent);
+            } catch (RemoteException re) {
+            }
+            return;
+        }
         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
         final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
@@ -15378,6 +15455,12 @@
         });
     }
 
+    private boolean isCallerSameAsInstaller(int callingUid, String pkgName) {
+        final int installerPkgUid = getPackageUid(getInstallerPackageName(pkgName),
+                0 /* flags */, UserHandle.getUserId(callingUid));
+        return installerPkgUid == callingUid;
+    }
+
     private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
         int[] result = EMPTY_INT_ARRAY;
         for (int userId : userIds) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 827b88a..1acc955 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -667,6 +667,12 @@
                 // - version code hasn't change
                 // - lastUpdateTime hasn't change
                 // - all target activities are still enabled.
+
+                // Note, system apps timestamps do *not* change after OTAs.  (But they do
+                // after an adb sync or a local flash.)
+                // This means if a system app's version code doesn't change on an OTA,
+                // we don't notice it's updated.  But that's fine since their version code *should*
+                // really change on OTAs.
                 if ((getPackageInfo().getVersionCode() == pi.versionCode)
                         && (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
                         && areAllActivitiesStillEnabled()) {
@@ -1145,6 +1151,17 @@
         }
     }
 
+    /** @return true if there's any shortcuts that are not manifest shortcuts. */
+    public boolean hasNonManifestShortcuts() {
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+            if (!si.isDeclaredInManifest()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.println();
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 79b5c4e..1780058 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -40,7 +40,7 @@
 
     private final ShortcutPackageInfo mPackageInfo;
 
-    protected final ShortcutUser mShortcutUser;
+    protected ShortcutUser mShortcutUser;
 
     protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
             int packageUserId, @NonNull String packageName,
@@ -51,6 +51,13 @@
         mPackageInfo = Preconditions.checkNotNull(packageInfo);
     }
 
+    /**
+     * Change the parent {@link ShortcutUser}.  Need it in the restore code.
+     */
+    public void replaceUser(ShortcutUser user) {
+        mShortcutUser = user;
+    }
+
     public ShortcutUser getUser() {
         return mShortcutUser;
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c1fc7f11..2c61f75 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -54,6 +54,7 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -324,10 +325,30 @@
         int CHECK_LAUNCHER_ACTIVITY = 12;
         int IS_ACTIVITY_ENABLED = 13;
         int PACKAGE_UPDATE_CHECK = 14;
+        int ASYNC_PRELOAD_USER_DELAY = 15;
 
-        int COUNT = PACKAGE_UPDATE_CHECK + 1;
+        int COUNT = ASYNC_PRELOAD_USER_DELAY + 1;
     }
 
+    private static final String[] STAT_LABELS = {
+            "getHomeActivities()",
+            "Launcher permission check",
+            "getPackageInfo()",
+            "getPackageInfo(SIG)",
+            "getApplicationInfo",
+            "cleanupDanglingBitmaps",
+            "getActivity+metadata",
+            "getInstalledPackages",
+            "checkPackageChanges",
+            "getApplicationResources",
+            "resourceNameLookup",
+            "getLauncherActivity",
+            "checkLauncherActivity",
+            "isActivityEnabled",
+            "packageUpdateCheck",
+            "asyncPreloadUserDelay"
+    };
+
     final Object mStatLock = new Object();
 
     @GuardedBy("mStatLock")
@@ -359,6 +380,12 @@
     @GuardedBy("mLock")
     private Exception mLastWtfStacktrace;
 
+    static class InvalidFileFormatException extends Exception {
+        public InvalidFileFormatException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
     public ShortcutService(Context context) {
         this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
     }
@@ -533,19 +560,26 @@
     /** lifecycle event */
     void handleUnlockUser(int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "handleUnlockUser: user=" + userId);
+        Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mLock) {
             mUnlockedUsers.put(userId, true);
-
-            // Preload the user's shortcuts.
-            // Also see if the locale has changed.
-            // Note as of nyc, the locale is per-user, so the locale shouldn't change
-            // when the user is locked.  However due to b/30119489 it still happens.
-            getUserShortcutsLocked(userId).detectLocaleChange();
-
-            checkPackageChanges(userId);
         }
+
+        // Preload the user data.
+        // Note, we don't use mHandler here but instead just start a new thread.
+        // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
+        // busy at this point and this could take hundreds of milliseconds, which would be too
+        // late since the launcher would already have started.
+        // So we just create a new thread.  This code runs rarely, so we don't use a thread pool
+        // or anything.
+        final long start = injectElapsedRealtime();
+        injectRunOnNewThread(() -> {
+            synchronized (mLock) {
+                logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
+                getUserShortcutsLocked(userId);
+            }
+        });
     }
 
     /** lifecycle event */
@@ -933,7 +967,7 @@
         try {
             final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
             return ret;
-        } catch (IOException | XmlPullParserException e) {
+        } catch (IOException | XmlPullParserException | InvalidFileFormatException e) {
             Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
             return null;
         } finally {
@@ -942,7 +976,8 @@
     }
 
     private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
-            boolean fromBackup) throws XmlPullParserException, IOException {
+            boolean fromBackup) throws XmlPullParserException, IOException,
+            InvalidFileFormatException {
 
         final BufferedInputStream bis = new BufferedInputStream(is);
 
@@ -1110,6 +1145,9 @@
                 userPackages = new ShortcutUser(this, userId);
             }
             mUsers.put(userId, userPackages);
+
+            // Also when a user's data is first accessed, scan all packages.
+            checkPackageChanges(userId);
         }
         return userPackages;
     }
@@ -1468,6 +1506,10 @@
         mHandler.post(r);
     }
 
+    void injectRunOnNewThread(Runnable r) {
+        new Thread(r).start();
+    }
+
     /**
      * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
      *                                  {@link #getMaxActivityShortcuts()}.
@@ -2625,10 +2667,14 @@
             boolean forceRescan) {
         final ShortcutUser user = getUserShortcutsLocked(userId);
 
+        // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
+        // is not reliable.
         final long now = injectCurrentTimeMillis();
+        final boolean afterOta =
+                !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
 
         // Then for each installed app, publish manifest shortcuts when needed.
-        forUpdatedPackages(userId, lastScanTime, ai -> {
+        forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
             user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
             user.rescanPackageIfNeeded(ai.packageName, forceRescan);
         });
@@ -2636,6 +2682,7 @@
         // Write the time just before the scan, because there may be apps that have just
         // been updated, and we want to catch them in the next time.
         user.setLastAppScanTime(now);
+        user.setLastAppScanOsFingerprint(injectBuildFingerprint());
         scheduleSaveUser(userId);
     }
 
@@ -2874,7 +2921,7 @@
         return parceledList.getList();
     }
 
-    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime,
+    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
             Consumer<ApplicationInfo> callback) {
         if (DEBUG) {
             Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
@@ -2886,7 +2933,8 @@
             // If the package has been updated since the last scan time, then scan it.
             // Also if it's a system app with no update, lastUpdateTime is not reliable, so
             // just scan it.
-            if (pi.lastUpdateTime >= lastScanTime || isPureSystemApp(pi.applicationInfo)) {
+            if (pi.lastUpdateTime >= lastScanTime
+                    || (afterOta && isPureSystemApp(pi.applicationInfo))) {
                 if (DEBUG) {
                     Slog.d(TAG, "Found updated package " + pi.packageName);
                 }
@@ -3129,15 +3177,16 @@
                 wtf("Can't restore: user " + userId + " is locked or not running");
                 return;
             }
-            final ShortcutUser user;
+            // Actually do restore.
+            final ShortcutUser restored;
             final ByteArrayInputStream is = new ByteArrayInputStream(payload);
             try {
-                user = loadUserInternal(userId, is, /* fromBackup */ true);
-            } catch (XmlPullParserException | IOException e) {
+                restored = loadUserInternal(userId, is, /* fromBackup */ true);
+            } catch (XmlPullParserException | IOException | InvalidFileFormatException e) {
                 Slog.w(TAG, "Restoration failed.", e);
                 return;
             }
-            mUsers.put(userId, user);
+            getUserShortcutsLocked(userId).mergeRestoredFile(restored);
 
             // Rescan all packages to re-publish manifest shortcuts and do other checks.
             rescanUpdatedPackagesLocked(userId,
@@ -3218,23 +3267,9 @@
 
             pw.println("  Stats:");
             synchronized (mStatLock) {
-                final String p = "    ";
-                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
-                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
-
-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
-                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
-                dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
-                dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata");
-                dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages");
-                dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
-                dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources");
-                dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
-                dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
-                dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
-                dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
-                dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
+                for (int i = 0; i < Stats.COUNT; i++) {
+                    dumpStatLS(pw, "    ", i);
+                }
             }
 
             pw.println();
@@ -3277,12 +3312,12 @@
         return tobj.format("%Y-%m-%d %H:%M:%S");
     }
 
-    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+    private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
         pw.print(prefix);
         final int count = mCountStats[statId];
         final long dur = mDurationStats[statId];
         pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
-                label, count, dur,
+                STAT_LABELS[statId], count, dur,
                 (count == 0 ? 0 : ((double) dur) / count)));
     }
 
@@ -3578,6 +3613,12 @@
         Binder.restoreCallingIdentity(token);
     }
 
+    // Injection point.
+    @VisibleForTesting
+    String injectBuildFingerprint() {
+        return Build.FINGERPRINT;
+    }
+
     final void wtf(String message) {
         wtf(message, /* exception= */ null);
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index ce3ed9c..5d4bfa4 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,12 +23,14 @@
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.server.pm.ShortcutService.InvalidFileFormatException;
 
 import libcore.util.Objects;
 
@@ -60,6 +62,7 @@
 
     // Suffix "2" was added to force rescan all packages after the next OTA.
     private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
+    private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
     private static final String KEY_USER_ID = "userId";
     private static final String KEY_LAUNCHERS = "launchers";
     private static final String KEY_PACKAGES = "packages";
@@ -125,6 +128,8 @@
 
     private long mLastAppScanTime;
 
+    private String mLastAppScanOsFingerprint;
+
     public ShortcutUser(ShortcutService service, int userId) {
         mService = service;
         mUserId = userId;
@@ -142,6 +147,14 @@
         mLastAppScanTime = lastAppScanTime;
     }
 
+    public String getLastAppScanOsFingerprint() {
+        return mLastAppScanOsFingerprint;
+    }
+
+    public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
+        mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
+    }
+
     // We don't expose this directly to non-test code because only ShortcutUser should add to/
     // remove from it.
     @VisibleForTesting
@@ -153,6 +166,11 @@
         return mPackages.containsKey(packageName);
     }
 
+    private void addPackage(@NonNull ShortcutPackage p) {
+        p.replaceUser(this);
+        mPackages.put(p.getPackageName(), p);
+    }
+
     public ShortcutPackage removePackage(@NonNull String packageName) {
         final ShortcutPackage removed = mPackages.remove(packageName);
 
@@ -168,7 +186,8 @@
         return mLaunchers;
     }
 
-    public void addLauncher(ShortcutLauncher launcher) {
+    private void addLauncher(ShortcutLauncher launcher) {
+        launcher.replaceUser(this);
         mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
                 launcher.getPackageName()), launcher);
     }
@@ -315,11 +334,16 @@
             throws IOException, XmlPullParserException {
         out.startTag(null, TAG_ROOT);
 
-        ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
-        ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
-                mLastAppScanTime);
+        if (!forBackup) {
+            // Don't have to back them up.
+            ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
+            ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
+                    mLastAppScanTime);
+            ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
+                    mLastAppScanOsFingerprint);
 
-        ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
+            ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
+        }
 
         // Can't use forEachPackageItem due to the checked exceptions.
         {
@@ -352,53 +376,59 @@
     }
 
     public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
-            boolean fromBackup) throws IOException, XmlPullParserException {
+            boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
         final ShortcutUser ret = new ShortcutUser(s, userId);
 
-        ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
-                ATTR_KNOWN_LOCALES);
+        try {
+            ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
+                    ATTR_KNOWN_LOCALES);
 
-        // If lastAppScanTime is in the future, that means the clock went backwards.
-        // Just scan all apps again.
-        final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
-                ATTR_LAST_APP_SCAN_TIME);
-        final long currentTime = s.injectCurrentTimeMillis();
-        ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
+            // If lastAppScanTime is in the future, that means the clock went backwards.
+            // Just scan all apps again.
+            final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
+                    ATTR_LAST_APP_SCAN_TIME);
+            final long currentTime = s.injectCurrentTimeMillis();
+            ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
+            ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
+                    ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
+            final int outerDepth = parser.getDepth();
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                final int depth = parser.getDepth();
+                final String tag = parser.getName();
 
-        final int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            final int depth = parser.getDepth();
-            final String tag = parser.getName();
+                if (depth == outerDepth + 1) {
+                    switch (tag) {
+                        case TAG_LAUNCHER: {
+                            ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
+                                    parser, ATTR_VALUE);
+                            continue;
+                        }
+                        case ShortcutPackage.TAG_ROOT: {
+                            final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
+                                    s, ret, parser, fromBackup);
 
-            if (depth == outerDepth + 1) {
-                switch (tag) {
-                    case TAG_LAUNCHER: {
-                        ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
-                                parser, ATTR_VALUE);
-                        continue;
-                    }
-                    case ShortcutPackage.TAG_ROOT: {
-                        final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
-                                s, ret, parser, fromBackup);
+                            // Don't use addShortcut(), we don't need to save the icon.
+                            ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
+                            continue;
+                        }
 
-                        // Don't use addShortcut(), we don't need to save the icon.
-                        ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
-                        continue;
-                    }
-
-                    case ShortcutLauncher.TAG_ROOT: {
-                        ret.addLauncher(
-                                ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
-                        continue;
+                        case ShortcutLauncher.TAG_ROOT: {
+                            ret.addLauncher(
+                                    ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
+                            continue;
+                        }
                     }
                 }
+                ShortcutService.warnForInvalidTag(depth, tag);
             }
-            ShortcutService.warnForInvalidTag(depth, tag);
+        } catch (RuntimeException e) {
+            throw new ShortcutService.InvalidFileFormatException(
+                    "Unable to parse file", e);
         }
         return ret;
     }
@@ -447,6 +477,51 @@
         }
     }
 
+    public void mergeRestoredFile(ShortcutUser restored) {
+        final ShortcutService s = mService;
+        // Note, a restore happens only at the end of setup wizard.  At this point, no apps are
+        // installed from Play Store yet, but it's still possible that system apps have already
+        // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
+        // When such a system app has allowbackup=true, then we go ahead and replace all existing
+        // shortcuts with the restored shortcuts.  (Then we'll re-publish manifest shortcuts later
+        // in the call site.)
+        // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
+        // already been published.  So we selectively add restored ShortcutPackages here.
+        //
+        // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
+        // without users interaction it's really not a big deal, so we just clear existing
+        // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
+
+        mLaunchers.clear();
+        restored.forAllLaunchers(sl -> {
+            // If the app is already installed and allowbackup = false, then ignore the restored
+            // data.
+            if (s.isPackageInstalled(sl.getPackageName(), getUserId())
+                    && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
+                return;
+            }
+            addLauncher(sl);
+        });
+        restored.forAllPackages(sp -> {
+            // If the app is already installed and allowbackup = false, then ignore the restored
+            // data.
+            if (s.isPackageInstalled(sp.getPackageName(), getUserId())
+                    && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
+                return;
+            }
+
+            final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
+            if (previous != null && previous.hasNonManifestShortcuts()) {
+                Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
+                        + " Existing non-manifeset shortcuts will be overwritten.");
+            }
+            addPackage(sp);
+        });
+        // Empty the launchers and packages in restored to avoid accidentally using them.
+        restored.mLaunchers.clear();
+        restored.mPackages.clear();
+    }
+
     public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.print(prefix);
         pw.print("User: ");
@@ -457,6 +532,8 @@
         pw.print(mLastAppScanTime);
         pw.print("] ");
         pw.print(ShortcutService.formatTime(mLastAppScanTime));
+        pw.print("  Last app scan FP: ");
+        pw.print(mLastAppScanOsFingerprint);
         pw.println();
 
         prefix += prefix + "  ";
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c9ad49a..af055da 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -180,7 +180,8 @@
             UserInfo.FLAG_MANAGED_PROFILE
             | UserInfo.FLAG_EPHEMERAL
             | UserInfo.FLAG_RESTRICTED
-            | UserInfo.FLAG_GUEST;
+            | UserInfo.FLAG_GUEST
+            | UserInfo.FLAG_DEMO;
 
     private static final int MIN_USER_ID = 10;
     // We need to keep process uid within Integer.MAX_VALUE.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a39add8..ec07812 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5318,15 +5318,18 @@
         boolean showing = mKeyguardDelegate.isShowing();
         if (wasOccluded && !isOccluded && showing) {
             mKeyguardOccluded = false;
-            mKeyguardDelegate.setOccluded(false);
+            mKeyguardDelegate.setOccluded(false, true /* animate */);
             mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
             if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
                 mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
             }
+            Animation anim = AnimationUtils.loadAnimation(mContext,
+                    com.android.internal.R.anim.wallpaper_open_exit);
+            mWindowManagerFuncs.overridePlayingAppAnimationsLw(anim);
             return true;
         } else if (!wasOccluded && isOccluded && showing) {
             mKeyguardOccluded = true;
-            mKeyguardDelegate.setOccluded(true);
+            mKeyguardDelegate.setOccluded(true, false /* animate */);
             mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
             mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
             return true;
@@ -6397,6 +6400,9 @@
             }
 
             mWindowManagerDrawComplete = true;
+            if (mKeyguardDelegate != null) {
+                mKeyguardDelegate.onDrawCompleteLw();
+            }
         }
 
         finishScreenTurningOn();
@@ -6866,7 +6872,8 @@
     /** {@inheritDoc} */
     @Override
     public void systemReady() {
-        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
+                mWindowManagerFuncs.getWindowManagerLock());
         mKeyguardDelegate.onSystemReady();
 
         readCameraLensCoverState();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 4fce49e..acf855f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -19,6 +19,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy.OnKeyguardExitResult;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
@@ -43,6 +44,7 @@
     private static final int INTERACTIVE_STATE_AWAKE = 1;
     private static final int INTERACTIVE_STATE_GOING_TO_SLEEP = 2;
 
+    private final Object mWindowManagerLock;
     protected KeyguardServiceWrapper mKeyguardService;
     private final Context mContext;
     private final View mScrim; // shown if keyguard crashes
@@ -50,6 +52,9 @@
     private final KeyguardState mKeyguardState = new KeyguardState();
     private DrawnListener mDrawnListenerWhenConnect;
 
+    @GuardedBy("mWindowManagerLock")
+    private boolean mHideScrimPending;
+
     private static final class KeyguardState {
         KeyguardState() {
             // Assume keyguard is showing and secure until we know for sure. This is here in
@@ -92,10 +97,12 @@
         @Override
         public void onDrawn() throws RemoteException {
             if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
+            synchronized (mWindowManagerLock) {
+                mHideScrimPending = true;
+            }
             if (mDrawnListener != null) {
                 mDrawnListener.onDrawn();
             }
-            hideScrim();
         }
     };
 
@@ -116,7 +123,8 @@
         }
     };
 
-    public KeyguardServiceDelegate(Context context) {
+    public KeyguardServiceDelegate(Context context, Object windowManagerLock) {
+        mWindowManagerLock = windowManagerLock;
         mContext = context;
         mScrimHandler = UiThread.getHandler();
         mScrim = createScrim(context, mScrimHandler);
@@ -180,7 +188,7 @@
                 mKeyguardService.onBootCompleted();
             }
             if (mKeyguardState.occluded) {
-                mKeyguardService.setOccluded(mKeyguardState.occluded);
+                mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
             }
         }
 
@@ -232,10 +240,10 @@
         }
     }
 
-    public void setOccluded(boolean isOccluded) {
+    public void setOccluded(boolean isOccluded, boolean animate) {
         if (mKeyguardService != null) {
-            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ")");
-            mKeyguardService.setOccluded(isOccluded);
+            if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate);
+            mKeyguardService.setOccluded(isOccluded, animate);
         }
         mKeyguardState.occluded = isOccluded;
     }
@@ -355,6 +363,16 @@
         }
     }
 
+    /**
+     * Called when all windows were fully drawn.
+     */
+    public void onDrawCompleteLw() {
+        if (mHideScrimPending) {
+            hideScrim();
+            mHideScrimPending = false;
+        }
+    }
+
     private static View createScrim(Context context, Handler handler) {
         final View view = new View(context);
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 55652fe..2169927 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -63,9 +63,9 @@
     }
 
     @Override // Binder interface
-    public void setOccluded(boolean isOccluded) {
+    public void setOccluded(boolean isOccluded, boolean animate) {
         try {
-            mService.setOccluded(isOccluded);
+            mService.setOccluded(isOccluded, animate);
         } catch (RemoteException e) {
             Slog.w(TAG , "Remote Exception", e);
         }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d9c4254..a7b9cf4 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -102,9 +102,8 @@
     private static final int MSG_START_USER = 7;
     private static final int MSG_CLEANUP_USER = 8;
     private static final int MSG_SWITCH_USER = 9;
-    private static final int MSG_SET_DEVICE_LOCKED = 10;
-    private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 11;
-    private static final int MSG_UNLOCK_USER = 12;
+    private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 10;
+    private static final int MSG_UNLOCK_USER = 11;
 
     private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
 
@@ -317,20 +316,6 @@
         }
     }
 
-    public void setDeviceLockedForUser(int userId, boolean locked) {
-        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
-            synchronized (mDeviceLockedForUser) {
-                mDeviceLockedForUser.put(userId, locked);
-            }
-            if (locked) {
-                try {
-                    ActivityManagerNative.getDefault().notifyLockedProfile(userId);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-    }
-
     boolean isDeviceLockedInner(int userId) {
         synchronized (mDeviceLockedForUser) {
             return mDeviceLockedForUser.get(userId, true);
@@ -838,10 +823,24 @@
         }
 
         @Override
-        public void setDeviceLockedForUser(int userId, boolean value) {
+        public void setDeviceLockedForUser(int userId, boolean locked) {
             enforceReportPermission();
-            mHandler.obtainMessage(MSG_SET_DEVICE_LOCKED, value ? 1 : 0, userId)
-                    .sendToTarget();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+                    synchronized (mDeviceLockedForUser) {
+                        mDeviceLockedForUser.put(userId, locked);
+                    }
+                    if (locked) {
+                        try {
+                            ActivityManagerNative.getDefault().notifyLockedProfile(userId);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
 
         @Override
@@ -917,9 +916,6 @@
                     mCurrentUser = msg.arg1;
                     refreshDeviceLockedForUser(UserHandle.USER_ALL);
                     break;
-                case MSG_SET_DEVICE_LOCKED:
-                    setDeviceLockedForUser(msg.arg2, msg.arg1 != 0);
-                    break;
                 case MSG_FLUSH_TRUST_USUALLY_MANAGED:
                     SparseBooleanArray usuallyManaged;
                     synchronized (mTrustUsuallyManagedForUser) {
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index acd6587..db7df25 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -151,7 +151,7 @@
     }
 
     private void startListening() {
-        if (DEBUG) Slog.d(TAG, "startListening");
+        Slog.d(TAG, "startListening");
 
         // Start listening for location updates (default: low power, max 1h, min 10m).
         mLocationManager.requestLocationUpdates(
@@ -173,7 +173,7 @@
             mTimeChangedReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    if (DEBUG) Slog.d(TAG, "onReceive: " + intent);
+                    Slog.d(TAG, "onReceive: " + intent);
                     updateTwilightState();
                 }
             };
@@ -188,7 +188,7 @@
     }
 
     private void stopListening() {
-        if (DEBUG) Slog.d(TAG, "stopListening");
+        Slog.d(TAG, "stopListening");
 
         if (mTimeChangedReceiver != null) {
             getContext().unregisterReceiver(mTimeChangedReceiver);
@@ -241,15 +241,20 @@
 
     @Override
     public void onAlarm() {
-        if (DEBUG) Slog.d(TAG, "onAlarm");
+        Slog.d(TAG, "onAlarm");
         updateTwilightState();
     }
 
     @Override
     public void onLocationChanged(Location location) {
-        if (DEBUG) Slog.d(TAG, "onLocationChanged: " + location);
-        mLastLocation = location;
-        updateTwilightState();
+        if (location != null) {
+            Slog.d(TAG, "onLocationChanged:"
+                    + " provider=" + location.getProvider()
+                    + " accuracy=" + location.getAccuracy()
+                    + " time=" + location.getTime());
+            mLastLocation = location;
+            updateTwilightState();
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 621e43a..a8a0b0e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -30,6 +30,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.wm.WindowManagerService.H;
@@ -44,6 +45,7 @@
 import android.view.IApplicationToken;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -838,6 +840,18 @@
         }
     }
 
+    /**
+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
+     */
+    void overridePlayingAppAnimations(Animation a) {
+        if (mAppAnimator.isAnimating()) {
+            final WindowState win = findMainWindow();
+            final int width = win.mContainingFrame.width();
+            final int height = win.mContainingFrame.height();
+            mAppAnimator.setAnimation(a, width, height, false, STACK_CLIP_NONE);
+        }
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1d57872..9b5b101 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -35,6 +35,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.animation.Animation;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -637,7 +638,7 @@
      */
     TaskStack getDockedStackVisibleForUserLocked() {
         final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
-        return (stack != null && stack.isVisibleForUserLocked()) ? stack : null;
+        return (stack != null && stack.isVisibleLocked(true /* ignoreKeyguard */)) ? stack : null;
     }
 
     /**
@@ -674,4 +675,13 @@
 
         return touchedWin;
     }
+
+    /**
+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}.
+     */
+    void overridePlayingAppAnimationsLw(Animation a) {
+        for (int i = mStacks.size() - 1; i >= 0; i--) {
+            mStacks.get(i).overridePlayingAppAnimations(a);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1dcada6..ca183010 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -38,6 +38,7 @@
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.animation.Animation;
 
 import com.android.server.EventLogTags;
 
@@ -677,19 +678,6 @@
         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
     }
 
-    boolean isVisibleForUser() {
-        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            final AppWindowToken appToken = mAppTokens.get(i);
-            for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
-                WindowState window = appToken.allAppWindows.get(j);
-                if (!window.isHiddenFromUserLocked()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     boolean isVisible() {
         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
             final AppWindowToken appToken = mAppTokens.get(i);
@@ -778,6 +766,15 @@
         return mStack.getDisplayContent().getDisplayInfo();
     }
 
+    /**
+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
+     */
+    void overridePlayingAppAnimations(Animation a) {
+        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+            mAppTokens.get(i).overridePlayingAppAnimations(a);
+        }
+    }
+
     @Override
     public String toString() {
         return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 8be5b19..8f8f642 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -44,6 +44,7 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.view.animation.Animation;
 
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
@@ -398,23 +399,21 @@
             return false;
         }
 
-        final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
         mTmpRect2.set(mBounds);
         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (mStackId == DOCKED_STACK_ID) {
             repositionDockedStackAfterRotation(mTmpRect2);
             snapDockedStackAfterRotation(mTmpRect2);
             final int newDockSide = getDockSide(mTmpRect2);
-            if (oldDockSide != newDockSide) {
-                // Update the dock create mode and clear the dock create bounds, these
-                // might change after a rotation and the original values will be invalid.
-                mService.setDockedStackCreateStateLocked(
-                        (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
-                        ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
-                        : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
-                        null);
-                mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
-            }
+
+            // Update the dock create mode and clear the dock create bounds, these
+            // might change after a rotation and the original values will be invalid.
+            mService.setDockedStackCreateStateLocked(
+                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
+                    ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
+                    : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
+                    null);
+            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
         }
 
         mBoundsAfterRotation.set(mTmpRect2);
@@ -890,7 +889,7 @@
             mAdjustImeAmount = adjustAmount;
             mAdjustDividerAmount = adjustDividerAmount;
             updateAdjustedBounds();
-            return isVisibleForUserLocked();
+            return isVisibleLocked(true /* ignoreKeyguard */);
         } else {
             return false;
         }
@@ -926,7 +925,7 @@
         if (minimizeAmount != mMinimizeAmount) {
             mMinimizeAmount = minimizeAmount;
             updateAdjustedBounds();
-            return isVisibleForUserLocked();
+            return isVisibleLocked(true /* ignoreKeyguard*/);
         } else {
             return false;
         }
@@ -943,7 +942,7 @@
     void beginImeAdjustAnimation() {
         for (int j = mTasks.size() - 1; j >= 0; j--) {
             final Task task = mTasks.get(j);
-            if (task.isVisibleForUser()) {
+            if (task.isVisible()) {
                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
                 task.addWindowsWaitingForDrawnIfResizingChanged();
             }
@@ -1233,9 +1232,13 @@
     }
 
     boolean isVisibleLocked() {
+        return isVisibleLocked(false /* ignoreKeyguard */);
+    }
+
+    boolean isVisibleLocked(boolean ignoreKeyguard) {
         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
                 && !mService.mAnimator.mKeyguardGoingAway;
-        if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
+        if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
             // The keyguard is showing and the stack shouldn't show on top of the keyguard.
             return false;
         }
@@ -1252,20 +1255,6 @@
         return false;
     }
 
-    /**
-     * @return true if a the stack is visible for the current in user, ignoring any other visibility
-     *         aspects, and false otherwise
-     */
-    boolean isVisibleForUserLocked() {
-        for (int i = mTasks.size() - 1; i >= 0; i--) {
-            final Task task = mTasks.get(i);
-            if (task.isVisibleForUser()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     boolean isDragResizing() {
         return mDragResizing;
     }
@@ -1379,4 +1368,13 @@
     public boolean getBoundsAnimating() {
         return mBoundsAnimating;
     }
+
+    /**
+     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
+     */
+    void overridePlayingAppAnimations(Animation a) {
+        for (int i = mTasks.size() - 1; i >= 0; --i) {
+            mTasks.get(i).overridePlayingAppAnimations(a);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 2b66c3a..e7ceba9 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -757,14 +757,16 @@
                 }
 
                 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
-                // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
+                // layer. For keyguard over wallpaper put the wallpaper under the lowest window that
+                // is currently on screen, i.e. not hidden by policy.
                 int insertionIndex = 0;
                 if (visible && wallpaperTarget != null) {
                     final int type = wallpaperTarget.mAttrs.type;
                     final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
                     if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
                             || type == TYPE_KEYGUARD_SCRIM) {
-                        insertionIndex = windows.indexOf(wallpaperTarget);
+                        insertionIndex = Math.min(windows.indexOf(wallpaperTarget),
+                                findLowestWindowOnScreen(windows));
                     }
                 }
                 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT
@@ -781,6 +783,21 @@
         return changed;
     }
 
+    /**
+     * @return The index in {@param windows} of the lowest window that is currently on screen and
+     *         not hidden by the policy.
+     */
+    private int findLowestWindowOnScreen(WindowList windows) {
+        final int size = windows.size();
+        for (int index = 0; index < size; index++) {
+            final WindowState win = windows.get(index);
+            if (win.isOnScreen()) {
+                return index;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
     boolean adjustWallpaperWindows() {
         mService.mWindowPlacerLocked.mWallpaperMayChange = false;
 
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b0d357c..47b0f3b 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -234,14 +234,12 @@
         boolean allowWhenLocked = false;
         // Show IME over the keyguard if the target allows it
         allowWhenLocked |= (win.mIsImWindow || imeTarget == win) && showImeOverKeyguard;
-        // Show SHOW_WHEN_LOCKED windows that turn on the screen
-        allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.mTurnOnScreen;
+        // Show SHOW_WHEN_LOCKED windows
+        allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
 
         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 dismiss keyguard.
+                    // Show error dialogs over apps that are shown on lockscreen
                     || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eb9ad6c..47a4114 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -249,6 +249,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -2908,12 +2909,11 @@
                     }
                     result |= RELAYOUT_RES_SURFACE_CHANGED;
                 }
-                final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
-                if (viewVisibility == View.VISIBLE && surfaceController != null) {
+                if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
                     // We already told the client to go invisible, but the message may not be
                     // handled yet, or it might want to draw a last frame. If we already have a
                     // surface, let the client use that, but don't create new surface at this point.
-                    surfaceController.getSurface(outSurface);
+                    winAnimator.mSurfaceController.getSurface(outSurface);
                 } else {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
 
@@ -5212,6 +5212,11 @@
         }
     }
 
+    @Override
+    public void overridePlayingAppAnimationsLw(Animation a) {
+        getDefaultDisplayContentLocked().overridePlayingAppAnimationsLw(a);
+    }
+
     /**
      * Re-sizes a stack and its containing tasks.
      * @param stackId Id of stack to resize.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e828650..a96cef0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3673,12 +3673,16 @@
 
     private boolean isActivePasswordSufficientForUserLocked(
             DevicePolicyData policy, int userHandle, boolean parent) {
-        if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent)
-                || policy.mActivePasswordLength < getPasswordMinimumLength(
+        final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
+        if (policy.mActivePasswordQuality < requiredPasswordQuality) {
+            return false;
+        }
+        if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+                && policy.mActivePasswordLength < getPasswordMinimumLength(
                         null, userHandle, parent)) {
             return false;
         }
-        if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+        if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
             return true;
         }
         return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(
diff --git a/services/net/Android.mk b/services/net/Android.mk
index 336bc45..408794e 100644
--- a/services/net/Android.mk
+++ b/services/net/Android.mk
@@ -7,4 +7,7 @@
 LOCAL_SRC_FILES += \
     $(call all-java-files-under,java)
 
+LOCAL_AIDL_INCLUDES += \
+    system/netd/server/binder
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 654ef18..6d90203 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -382,6 +382,7 @@
     private final State mStoppedState = new StoppedState();
     private final State mStoppingState = new StoppingState();
     private final State mStartedState = new StartedState();
+    private final State mRunningState = new RunningState();
 
     private final String mTag;
     private final Context mContext;
@@ -476,6 +477,7 @@
         // Super simple StateMachine.
         addState(mStoppedState);
         addState(mStartedState);
+            addState(mRunningState, mStartedState);
         addState(mStoppingState);
 
         setInitialState(mStoppedState);
@@ -570,7 +572,7 @@
         pw.decreaseIndent();
 
         pw.println();
-        pw.println("StateMachine dump:");
+        pw.println(mTag + " StateMachine dump:");
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
         pw.decreaseIndent();
@@ -768,6 +770,11 @@
         //         - IPv6 addresses
         //         - IPv6 routes
         //         - IPv6 DNS servers
+        //
+        // N.B.: this is fundamentally race-prone and should be fixed by
+        // changing NetlinkTracker from a hybrid edge/level model to an
+        // edge-only model, or by giving IpManager its own netlink socket(s)
+        // so as to track all required information directly.
         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
@@ -939,16 +946,30 @@
         return true;
     }
 
+    private void stopAllIP() {
+        // We don't need to worry about routes, just addresses, because:
+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
+        //     - we don't get IPv4 routes from netlink
+        // so we neither react to nor need to wait for changes in either.
+
+        try {
+            mNwService.disableIpv6(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to disable IPv6" + e);
+        }
+
+        try {
+            mNwService.clearInterfaceAddresses(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to clear addresses " + e);
+        }
+    }
+
 
     class StoppedState extends State {
         @Override
         public void enter() {
-            try {
-                mNwService.disableIpv6(mInterfaceName);
-                mNwService.clearInterfaceAddresses(mInterfaceName);
-            } catch (Exception e) {
-                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
-            }
+            stopAllIP();
 
             resetLinkProperties();
             if (mStartTimeMillis > 0) {
@@ -1023,12 +1044,71 @@
     }
 
     class StartedState extends State {
-        private boolean mDhcpActionInFlight;
-
         @Override
         public void enter() {
             mStartTimeMillis = SystemClock.elapsedRealtime();
 
+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mProvisioningTimeoutMs;
+                mProvisioningTimeoutAlarm.schedule(alarmTime);
+            }
+
+            if (readyToProceed()) {
+                transitionTo(mRunningState);
+            } else {
+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
+                // Clean up any leftover state from an abnormal exit from
+                // tethering or during an IpManager restart.
+                stopAllIP();
+            }
+        }
+
+        @Override
+        public void exit() {
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    if (readyToProceed()) {
+                        transitionTo(mRunningState);
+                    }
+                    break;
+
+                case EVENT_PROVISIONING_TIMEOUT:
+                    handleProvisioningFailure();
+                    break;
+
+                default:
+                    // It's safe to process messages out of order because the
+                    // only message that can both
+                    //     a) be received at this time and
+                    //     b) affect provisioning state
+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+                    deferMessage(msg);
+            }
+            return HANDLED;
+        }
+
+        boolean readyToProceed() {
+            return (!mLinkProperties.hasIPv4Address() &&
+                    !mLinkProperties.hasGlobalIPv6Address());
+        }
+    }
+
+    class RunningState extends State {
+        private boolean mDhcpActionInFlight;
+
+        @Override
+        public void enter() {
             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
                     mCallback, mMulticastFiltering);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
@@ -1037,12 +1117,6 @@
                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             }
 
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
             if (mConfiguration.mEnableIPv6) {
                 // TODO: Consider transitionTo(mStoppingState) if this fails.
                 startIPv6();
@@ -1070,7 +1144,6 @@
 
         @Override
         public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
             stopDhcpAction();
 
             if (mIpReachabilityMonitor != null) {
@@ -1167,10 +1240,6 @@
                     break;
                 }
 
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
                 case EVENT_DHCPACTION_TIMEOUT:
                     stopDhcpAction();
                     break;
diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java
new file mode 100644
index 0000000..153cb50
--- /dev/null
+++ b/services/net/java/android/net/util/NetdService.java
@@ -0,0 +1,46 @@
+/*
+ * 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.net.util;
+
+import android.net.INetd;
+import android.os.ServiceManager;
+import android.util.Log;
+
+
+/**
+ * @hide
+ */
+public class NetdService {
+    private static final String TAG = NetdService.class.getSimpleName();
+    private static final String NETD_SERVICE_NAME = "netd";
+
+    /**
+     * It is the caller's responsibility to check for a null return value
+     * and to handle RemoteException errors from invocations on the returned
+     * interface if, for example, netd dies and is restarted.
+     *
+     * @return an INetd instance or null.
+     */
+    public static INetd getInstance() {
+        final INetd netdInstance = INetd.Stub.asInterface(
+                ServiceManager.getService(NETD_SERVICE_NAME));
+        if (netdInstance == null) {
+            Log.w(TAG, "WARNING: returning null INetd instance.");
+        }
+        return netdInstance;
+    }
+}
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 07cc9c0..07b26e8 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -57,6 +57,9 @@
  * spooler if needed, to make the timed remote calls, to handle
  * remote exceptions, and to bind/unbind to the remote instance as
  * needed.
+ *
+ * The calls might be blocking and need the main thread of to be unblocked to finish. Hence do not
+ * call this while holding any monitors that might need to be acquired the main thread.
  */
 final class RemotePrintSpooler {
 
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 05301c1..a91cdb3 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -434,12 +434,12 @@
     }
 
     public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
+        mSpooler.clearCustomPrinterIconCache();
+
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
             if (mPrinterDiscoverySession == null) {
-                mSpooler.clearCustomPrinterIconCache();
-
                 // If we do not have a session, tell all service to create one.
                 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
                     @Override
@@ -731,6 +731,8 @@
 
     @Override
     public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+        mSpooler.onCustomPrinterIconLoaded(printerId, icon);
+
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
@@ -738,7 +740,6 @@
             if (mPrinterDiscoverySession == null) {
                 return;
             }
-            mSpooler.onCustomPrinterIconLoaded(printerId, icon);
             mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
         }
     }
@@ -979,18 +980,21 @@
      * Prune persistent state if a print service was uninstalled
      */
     public void prunePrintServices() {
+        ArrayList<ComponentName> installedComponents;
+
         synchronized (mLock) {
-            ArrayList<ComponentName> installedComponents = getInstalledComponents();
+            installedComponents = getInstalledComponents();
 
             // Remove unnecessary entries from persistent state "disabled services"
             boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents);
             if (disabledServicesUninstalled) {
                 writeDisabledPrintServicesLocked(mDisabledServices);
             }
-
-            // Remove unnecessary entries from persistent state "approved services"
-            mSpooler.pruneApprovedPrintServices(installedComponents);
         }
+
+        // Remove unnecessary entries from persistent state "approved services"
+        mSpooler.pruneApprovedPrintServices(installedComponents);
+
     }
 
     private void onConfigurationChangedLocked() {
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 404c142..a3d0afa 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.when;
 
 import android.accounts.Account;
+import android.accounts.AccountManagerInternal;
 import android.accounts.AuthenticatorDescription;
 import android.app.AppOpsManager;
 import android.app.Notification;
@@ -44,6 +45,8 @@
 import android.test.mock.MockPackageManager;
 import android.util.Log;
 
+import com.android.server.LocalServices;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -73,6 +76,7 @@
         SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
         SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
         SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
+        LocalServices.removeServiceForTest(AccountManagerInternal.class);
         super.tearDown();
     }
 
@@ -282,6 +286,7 @@
 
     private AccountManagerService createAccountManagerService(Context mockContext,
             Context realContext) {
+        LocalServices.removeServiceForTest(AccountManagerInternal.class);
         return new MyAccountManagerService(mockContext,
                 new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
     }
@@ -420,6 +425,11 @@
         public int checkSignatures(final int uid1, final int uid2) {
             return PackageManager.SIGNATURE_MATCH;
         }
+
+        @Override
+        public void addOnPermissionsChangeListener(
+                OnPermissionsChangedListener listener) {
+        }
     }
 
     static public class MyAccountManagerService extends AccountManagerService {
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 e440a0d..984a484 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -62,7 +62,7 @@
         for (int i = 0; i < 100; i++) {
             taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true);
         }
-        mTaskPersister.maybeWritePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
+        mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
         SparseBooleanArray newTaskIdsOnFile = mTaskPersister
                 .loadPersistedTaskIdsForUser(testUserId);
         assertTrue("TaskIds written differ from TaskIds read back from file",
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 1c7a138..792f300 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -390,6 +390,11 @@
         }
 
         @Override
+        void injectRunOnNewThread(Runnable r) {
+            runOnHandler(r);
+        }
+
+        @Override
         void injectEnforceCallingPermission(String permission, String message) {
             if (!mCallerPermissions.contains(permission)) {
                 throw new SecurityException("Missing permission: " + permission);
@@ -402,6 +407,11 @@
         }
 
         @Override
+        String injectBuildFingerprint() {
+            return mInjectedBuildFingerprint;
+        }
+
+        @Override
         void wtf(String message, Throwable th) {
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
@@ -523,6 +533,7 @@
     protected Map<String, PackageInfo> mInjectedPackages;
 
     protected Set<PackageWithUser> mUninstalledPackages;
+    protected Set<String> mSystemPackages;
 
     protected PackageManager mMockPackageManager;
     protected PackageManagerInternal mMockPackageManagerInternal;
@@ -623,6 +634,8 @@
     protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
     protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
 
+    protected String mInjectedBuildFingerprint = "build1";
+
     static {
         QUERY_ALL.setQueryFlags(
                 ShortcutQuery.FLAG_GET_ALL_KINDS);
@@ -672,6 +685,7 @@
                 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
         mUninstalledPackages = new HashSet<>();
+        mSystemPackages = new HashSet<>();
 
         mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
 
@@ -921,6 +935,12 @@
         });
     }
 
+    protected void setPackageLastUpdateTime(String packageName, long value) {
+        updatePackageInfo(packageName, pi -> {
+            pi.lastUpdateTime = value;
+        });
+    }
+
     protected void uninstallPackage(int userId, String packageName) {
         if (ENABLE_DUMP) {
             Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
@@ -952,6 +972,9 @@
         if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
             ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
+        if (mSystemPackages.contains(packageName)) {
+            ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        }
 
         if (getSignatures) {
             ret.signatures = pi.signatures;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 253334e..143398f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -3945,11 +3945,11 @@
         mInjectedPackages.remove(CALLING_PACKAGE_1);
         mInjectedPackages.remove(CALLING_PACKAGE_3);
 
-        mService.handleUnlockUser(USER_0);
+        mService.checkPackageChanges(USER_0);
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));  // ---------------
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
@@ -3961,7 +3961,7 @@
         assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
         assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
 
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
@@ -4154,7 +4154,7 @@
         updatePackageVersion(CALLING_PACKAGE_1, 1);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
 
         waitOnMainThread();
@@ -4186,10 +4186,13 @@
         mInjectedCurrentTimeMillis = START_TIME + 200;
 
         mRunningUsers.put(USER_10, true);
+        mUnlockedUsers.put(USER_10, true);
 
         reset(c0);
         reset(c10);
+        setPackageLastUpdateTime(CALLING_PACKAGE_1, mInjectedCurrentTimeMillis);
         mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4221,7 +4224,7 @@
         // Then send the broadcast, to only user-0.
                 mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4243,9 +4246,9 @@
         updatePackageVersion(CALLING_PACKAGE_3, 100);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4344,6 +4347,128 @@
         });
     }
 
+    public void testHandlePackageUpdate_systemAppUpdate() {
+
+        // Package1 is a system app.  Package 2 is not a system app, so it's not scanned
+        // in this test at all.
+        mSystemPackages.add(CALLING_PACKAGE_1);
+
+        // Initial state: no shortcuts.
+        mService.checkPackageChanges(USER_0);
+
+        assertEquals(mInjectedCurrentTimeMillis,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
+        assertEquals(mInjectedBuildFingerprint,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
+
+        // They have no shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Next.
+        // Update the packages -- now they have 1 manifest shortcut.
+        // But checkPackageChanges() don't notice it, since their version code / timestamp haven't
+        // changed.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Next.
+        // Update the build finger print.  All system apps will be scanned now.
+        mInjectedBuildFingerprint = "update1";
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Next.
+        // Update manifest shortcuts.
+        mInjectedBuildFingerprint = "update2";
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
+        // still not scanned.
+        mInjectedBuildFingerprint = "update2";
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Now update the version code, so CALLING_PACKAGE_1 is scanned again.
+        mInjectedBuildFingerprint = "update3";
+        mInjectedCurrentTimeMillis += 1000;
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1", "ms2");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
+        initService();
+        assertEquals(mInjectedCurrentTimeMillis,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
+        assertEquals(mInjectedBuildFingerprint,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
+    }
+
     public void testHandlePackageChanged() {
         final ComponentName ACTIVITY1 = new ComponentName(CALLING_PACKAGE_1, "act1");
         final ComponentName ACTIVITY2 = new ComponentName(CALLING_PACKAGE_1, "act2");
@@ -5234,6 +5359,12 @@
     /**
      * It's the case with preintalled apps -- when applyRestore() is called, the system
      * apps are already installed, so manifest shortcuts need to be re-published.
+     *
+     * Also, when a restore target app is already installed, and
+     * - if it has allowBackup=true, we'll restore normally, so all existing shortcuts will be
+     * replaced. (but manifest shortcuts will be re-published anyway.)  We log a warning on
+     * logcat.
+     * - if it has allowBackup=false, we don't touch any of the existing shortcuts.
      */
     public void testBackupAndRestore_appAlreadyInstalledWhenRestored() {
         // Pre-backup.  Same as testBackupAndRestore_manifestRePublished().
@@ -5265,6 +5396,19 @@
         mService.mPackageMonitor.onReceive(mServiceContext,
                 genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
 
+        // Set up shortcuts for package 3, which won't be backed up / restored.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_3, 1);
+        mService.mPackageMonitor.onReceive(mServiceContext,
+                genPackageAddIntent(CALLING_PACKAGE_3, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(getManager().setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+
         // Make sure the manifest shortcuts have been published.
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerShortcuts())
@@ -5290,6 +5434,11 @@
                     .areAllDisabled();
         });
 
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1", "ms1");
+        });
+
         // Backup and *without restarting the service, just call applyRestore()*.
         {
             int prevUid = mInjectedCallingUid;
@@ -5329,6 +5478,12 @@
                     .areAllNotDynamic()
             ;
         });
+
+        // Package 3 still has the same shortcuts.
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1", "ms1");
+        });
     }
 
     public void testSaveAndLoad_crossProfile() {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 43d2a1f..a04034e3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -535,6 +535,18 @@
                     + " user=" + userHandle);
         }
 
+        ComponentName getCurAssistant(int userHandle) {
+            String curAssistant = Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.ASSISTANT, userHandle);
+            if (TextUtils.isEmpty(curAssistant)) {
+                return null;
+            }
+            if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
+                    + " user=" + userHandle);
+            return ComponentName.unflattenFromString(curAssistant);
+        }
+
         void resetCurAssistant(int userHandle) {
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
                     Settings.Secure.ASSISTANT, null, userHandle);
@@ -1178,6 +1190,7 @@
                 synchronized (VoiceInteractionManagerServiceStub.this) {
                     ComponentName curInteractor = getCurInteractor(userHandle);
                     ComponentName curRecognizer = getCurRecognizer(userHandle);
+                    ComponentName curAssistant = getCurAssistant(userHandle);
                     if (curRecognizer == null) {
                         // Could a new recognizer appear when we don't have one pre-installed?
                         if (anyPackagesAppearing()) {
@@ -1196,6 +1209,7 @@
                             // the default config.
                             setCurInteractor(null, userHandle);
                             setCurRecognizer(null, userHandle);
+                            resetCurAssistant(userHandle);
                             initForUser(userHandle);
                             return;
                         }
@@ -1212,6 +1226,20 @@
                         return;
                     }
 
+                    if (curAssistant != null) {
+                        int change = isPackageDisappearing(curAssistant.getPackageName());
+                        if (change == PACKAGE_PERMANENT_CHANGE) {
+                            // If the currently set assistant is being removed, then we should
+                            // reset back to the default state (which is probably that we prefer
+                            // to have the default full voice interactor enabled).
+                            setCurInteractor(null, userHandle);
+                            setCurRecognizer(null, userHandle);
+                            resetCurAssistant(userHandle);
+                            initForUser(userHandle);
+                            return;
+                        }
+                    }
+
                     // There is no interactor, so just deal with a simple recognizer.
                     int change = isPackageDisappearing(curRecognizer.getPackageName());
                     if (change == PACKAGE_PERMANENT_CHANGE
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index dc9767c..d6a2ee3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -870,6 +870,11 @@
 
     /**
      * Flag indicating whether the carrier supports the Hold command while in an IMS call.
+     * <p>
+     * The device configuration value {@code config_device_respects_hold_carrier_config} ultimately
+     * controls whether this carrier configuration option is used.  Where
+     * {@code config_device_respects_hold_carrier_config} is false, the value of the
+     * {@link #KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} carrier configuration option is ignored.
      * @hide
      */
     public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
diff --git a/telephony/java/android/telephony/Rlog.java b/telephony/java/android/telephony/Rlog.java
index b4f400f..cd0a012 100644
--- a/telephony/java/android/telephony/Rlog.java
+++ b/telephony/java/android/telephony/Rlog.java
@@ -16,8 +16,15 @@
 
 package android.telephony;
 
+import android.text.TextUtils;
 import android.util.Log;
 
+import android.util.Base64;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
 /**
  * A class to log strings to the RADIO LOG.
  *
@@ -87,11 +94,52 @@
 
     /**
      * Redact personally identifiable information for production users.
-     * If log tag is loggable in verbose mode, return the original string, otherwise return XXX.
+     * @param tag used to identify the source of a log message
+     * @param pii the personally identifiable information we want to apply secure hash on.
+     * @return If tag is loggable in verbose mode or pii is null, return the original input.
+     * otherwise return a secure Hash of input pii
      */
     public static String pii(String tag, Object pii) {
-        return (isLoggable(tag, Log.VERBOSE) ? String.valueOf(pii) : "XXX");
+        String val = String.valueOf(pii);
+        if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) {
+            return val;
+        }
+        return "[" + secureHash(val.getBytes()) + "]";
     }
 
+    /**
+     * Redact personally identifiable information for production users.
+     * @param enablePiiLogging set when caller explicitly want to enable sensitive logging.
+     * @param pii the personally identifiable information we want to apply secure hash on.
+     * @return If enablePiiLogging is set to true or pii is null, return the original input.
+     * otherwise return a secure Hash of input pii
+     */
+    public static String pii(boolean enablePiiLogging, Object pii) {
+        String val = String.valueOf(pii);
+        if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) {
+            return val;
+        }
+        return "[" + secureHash(val.getBytes()) + "]";
+    }
+
+    /**
+     * Returns a secure hash (using the SHA1 algorithm) of the provided input.
+     *
+     * @return the hash
+     * @param input the bytes for which the secure hash should be computed.
+     */
+    private static String secureHash(byte[] input) {
+        MessageDigest messageDigest;
+
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            return "####";
+        }
+
+        byte[] result = messageDigest.digest(input);
+        return Base64.encodeToString(
+                result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+    }
 }
 
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 6229ed9..cf2d27e 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -340,7 +340,7 @@
         String iccIdToPrint = null;
         if (iccId != null) {
             if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
-                iccIdToPrint = iccId.substring(0, 9) + "XXXXXXXXXXX";
+                iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9));
             } else {
                 iccIdToPrint = iccId;
             }
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 2956d87..7ec46a3e 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -256,8 +256,8 @@
 
 
 def check_emoji_coverage(all_emoji, equivalent_emoji):
-  emoji_font = get_emoji_font()
-  check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
+    emoji_font = get_emoji_font()
+    check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji)
 
 
 def get_emoji_font():
@@ -274,15 +274,12 @@
         assert sequence in coverage, (
             '%s is not supported in the emoji font.' % printable(sequence))
 
-    # disable temporarily - we cover more than this
-    """
     for sequence in coverage:
         if sequence in {0x0000, 0x000D, 0x0020}:
             # The font needs to support a few extra characters, which is OK
             continue
         assert sequence in all_emoji, (
             'Emoji font should not support %s.' % printable(sequence))
-    """
 
     for first, second in sorted(equivalent_emoji.items()):
         assert coverage[first] == coverage[second], (
@@ -290,8 +287,6 @@
                 printable(first),
                 printable(second)))
 
-    # disable temporarily - some equivalent sequences we don't even know about
-    """
     for glyph in set(coverage.values()):
         maps_to_glyph = [seq for seq in coverage if coverage[seq] == glyph]
         if len(maps_to_glyph) > 1:
@@ -307,7 +302,7 @@
                 'The sequences %s should not result in the same glyph %s' % (
                     printable(equivalent_seqs),
                     glyph))
-    """
+
 
 def check_emoji_defaults(default_emoji):
     missing_text_chars = _emoji_properties['Emoji'] - default_emoji
@@ -334,15 +329,9 @@
     # Noto does not have monochrome glyphs for Unicode 7.0 wingdings and
     # webdings yet.
     missing_text_chars -= _chars_by_age['7.0']
-    # TODO: Remove these after b/26113320 is fixed
-    missing_text_chars -= {
-        0x263A, # WHITE SMILING FACE
-        0x270C, # VICTORY HAND
-        0x2744, # SNOWFLAKE
-        0x2764, # HEAVY BLACK HEART
-    }
     assert missing_text_chars == set(), (
-        'Text style version of some emoji characters are missing: ' + repr(missing_text_chars))
+        'Text style version of some emoji characters are missing: ' +
+            repr(missing_text_chars))
 
 
 # Setting reverse to true returns a dictionary that maps the values to sets of
@@ -362,7 +351,7 @@
             if not line:
                 continue
 
-            chars, prop = line.split(';')
+            chars, prop = line.split(';')[:2]
             chars = chars.strip()
             prop = prop.strip()
 
@@ -423,26 +412,6 @@
     _emoji_zwj_sequences = parse_unicode_datafile(
         path.join(ucd_path, 'emoji-zwj-sequences.txt'))
 
-    # filter modern pentathlon, as it seems likely to be removed from final spec
-    # also filter rifle
-    def is_excluded(n):
-        return n in [0x1f93b, 0x1f946]
-
-    def contains_excluded(t):
-        if type(t) == int:
-            return is_excluded(t)
-        return any(is_excluded(cp) for cp in t)
-
-    # filter modern pentathlon, as it seems likely to be removed from final spec
-    _emoji_properties['Emoji'] = set(
-        t for t in _emoji_properties['Emoji'] if not contains_excluded(t))
-    _emoji_sequences = dict(
-        (t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t))
-
-    # add in UN flag
-    UN_seq = flag_sequence('UN')
-    _emoji_sequences[UN_seq] = 'Emoji_Flag_Sequence'
-
 
 def flag_sequence(territory_code):
     return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
@@ -454,7 +423,8 @@
     flag_sequence('GF'), flag_sequence('GP'), flag_sequence('GS'),
     flag_sequence('MF'), flag_sequence('MQ'), flag_sequence('NC'),
     flag_sequence('PM'), flag_sequence('RE'), flag_sequence('TF'),
-    flag_sequence('WF'), flag_sequence('XK'), flag_sequence('YT'),
+    flag_sequence('UN'), flag_sequence('WF'), flag_sequence('XK'),
+    flag_sequence('YT'),
 })
 
 EQUIVALENT_FLAGS = {
@@ -467,6 +437,22 @@
 
 COMBINING_KEYCAP = 0x20E3
 
+# Characters that Android defaults to emoji style, different from the recommendations in UTR #51
+ANDROID_DEFAULT_EMOJI = frozenset({
+    0x2600, # BLACK SUN WITH RAYS
+    0x2601, # CLOUD
+    0x260E, # BLACK TELEPHONE
+    0x261D, # WHITE UP POINTING INDEX
+    0x263A, # WHITE SMILING FACE
+    0x2660, # BLACK SPADE SUIT
+    0x2663, # BLACK CLUB SUIT
+    0x2665, # BLACK HEART SUIT
+    0x2666, # BLACK DIAMOND SUIT
+    0x270C, # VICTORY HAND
+    0x2744, # SNOWFLAKE
+    0x2764, # HEAVY BLACK HEART
+})
+
 LEGACY_ANDROID_EMOJI = {
     0xFE4E5: flag_sequence('JP'),
     0xFE4E6: flag_sequence('US'),
@@ -502,7 +488,17 @@
 
 
 def is_fitzpatrick_modifier(cp):
-  return 0x1f3fb <= cp <= 0x1f3ff
+    return 0x1F3FB <= cp <= 0x1F3FF
+
+
+def reverse_emoji(seq):
+    rev = list(reversed(seq))
+    # if there are fitzpatrick modifiers in the sequence, keep them after
+    # the emoji they modify
+    for i in xrange(1, len(rev)):
+        if is_fitzpatrick_modifier(rev[i-1]):
+            rev[i], rev[i-1] = rev[i-1], rev[i]
+    return tuple(rev)
 
 
 def compute_expected_emoji():
@@ -511,26 +507,52 @@
     all_sequences = set()
     all_sequences.update(_emoji_variation_sequences)
 
+    # add zwj sequences not in the current emoji-zwj-sequences.txt
+    adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences)
+    adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences)
+    # single parent families
+    additional_emoji_zwj = (
+        (0x1F468, 0x200D, 0x1F466),
+        (0x1F468, 0x200D, 0x1F467),
+        (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466),
+        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466),
+        (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467),
+        (0x1F469, 0x200D, 0x1F466),
+        (0x1F469, 0x200D, 0x1F467),
+        (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466),
+        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466),
+        (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467),
+    )
+    # sequences formed from man and woman and optional fitzpatrick modifier
+    modified_extensions = (
+        0x2696,
+        0x2708,
+        0x1F3A8,
+        0x1F680,
+        0x1F692,
+    )
+    for seq in additional_emoji_zwj:
+        adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
+    for ext in modified_extensions:
+        for base in (0x1F468, 0x1F469):
+            seq = (base, 0x200D, ext)
+            adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
+            for modifier in range(0x1F3FB, 0x1F400):
+                seq = (base, modifier, 0x200D, ext)
+                adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence'
+
     for sequence in _emoji_sequences.keys():
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
         all_sequences.add(sequence)
         sequence_pieces.update(sequence)
 
-    for sequence in _emoji_zwj_sequences.keys():
+    for sequence in adjusted_emoji_zwj_sequences.keys():
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
         all_sequences.add(sequence)
         sequence_pieces.update(sequence)
         # Add reverse of all emoji ZWJ sequences, which are added to the fonts
         # as a workaround to get the sequences work in RTL text.
-        reversed_seq = list(reversed(sequence))
-        # if there are fitzpatrick modifiers in the sequence, keep them after
-        # the emoji they modify
-        for i in xrange(1, len(reversed_seq)):
-          if is_fitzpatrick_modifier(reversed_seq[i - 1]):
-            tmp = reversed_seq[i]
-            reversed_seq[i] = reversed_seq[i-1]
-            reversed_seq[i-1] = tmp
-        reversed_seq = tuple(reversed_seq)
+        reversed_seq = reverse_emoji(sequence)
         all_sequences.add(reversed_seq)
         equivalent_emoji[reversed_seq] = sequence
 
@@ -549,6 +571,7 @@
         set(LEGACY_ANDROID_EMOJI.keys()))
     default_emoji = (
         _emoji_properties['Emoji_Presentation'] |
+        ANDROID_DEFAULT_EMOJI |
         all_sequences |
         set(LEGACY_ANDROID_EMOJI.keys()))
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 9d0c20c..d3d5ea0 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -817,6 +817,7 @@
          */
         public static final int NETWORK_SELECTION_ENABLE = 0;
         /**
+         * @deprecated it is not used any more.
          * This network is disabled because higher layer (>2) network is bad
          */
         public static final int DISABLED_BAD_LINK = 1;
@@ -862,7 +863,7 @@
          */
         private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
                 "NETWORK_SELECTION_ENABLE",
-                "NETWORK_SELECTION_DISABLED_BAD_LINK",
+                "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
                 "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index bbc3d2f..1633bd9c9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -49,6 +49,8 @@
  * This class provides the primary API for managing all aspects of Wi-Fi
  * connectivity. Get an instance of this class by calling
  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
+ * On releases before NYC, it should only be obtained from an application context, and not from
+ * any other derived context to avoid memory leaks within the calling process.
 
  * It deals with several categories of items:
  * <ul>