Merge "Define a new config key for the recommendation provider app."
diff --git a/api/current.txt b/api/current.txt
index 5ecef52..a03ef38 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6200,6 +6200,7 @@
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
+    method public boolean clearResetPasswordToken(android.content.ComponentName);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
     method public android.content.Intent createAdminSupportIntent(java.lang.String);
     method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
@@ -6276,6 +6277,7 @@
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isResetPasswordTokenActive(android.content.ComponentName);
     method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
@@ -6287,6 +6289,7 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int);
     method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
@@ -6335,6 +6338,7 @@
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
     method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long);
+    method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index e89c25c..406d51c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6405,6 +6405,7 @@
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
+    method public boolean clearResetPasswordToken(android.content.ComponentName);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
     method public android.content.Intent createAdminSupportIntent(java.lang.String);
     method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
@@ -6495,6 +6496,7 @@
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isResetPasswordTokenActive(android.content.ComponentName);
     method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
@@ -6509,6 +6511,7 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int);
     method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
@@ -6559,6 +6562,7 @@
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
     method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long);
+    method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index b38e2b2..1be19ed 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6217,6 +6217,7 @@
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
+    method public boolean clearResetPasswordToken(android.content.ComponentName);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
     method public android.content.Intent createAdminSupportIntent(java.lang.String);
     method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
@@ -6298,6 +6299,7 @@
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isResetPasswordTokenActive(android.content.ComponentName);
     method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
@@ -6309,6 +6311,7 @@
     method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
     method public boolean requestBugreport(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int);
     method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
     method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
@@ -6357,6 +6360,7 @@
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
     method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long);
+    method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 7015381..b336472 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -53,6 +53,7 @@
 import android.os.HandlerThread;
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SELinux;
@@ -1004,7 +1005,8 @@
                 // In non-split user mode, userId can only be SYSTEM
                 int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
                 info = mUm.createRestrictedProfile(name, parentUserId);
-                mAm.addSharedAccountsFromParentUser(parentUserId, userId);
+                mAm.addSharedAccountsFromParentUser(parentUserId, userId,
+                        (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell");
             } else if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 0263681..7d039ef 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -1802,7 +1802,7 @@
     public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) {
         try {
             mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
-                    user.getIdentifier());
+                    user.getIdentifier(), mContext.getOpPackageName());
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index e0fdac1..49cd2c6 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -80,7 +80,7 @@
     /* Shared accounts */
     Account[] getSharedAccountsAsUser(int userId);
     boolean removeSharedAccountAsUser(in Account account, int userId);
-    void addSharedAccountsFromParentUser(int parentUserId, int userId);
+    void addSharedAccountsFromParentUser(int parentUserId, int userId, String opPackageName);
 
     /* Account renaming. */
     void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f1ccabe..0eb47a3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -28,6 +28,7 @@
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.IServiceConnection;
+import android.app.KeyguardManager;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -2694,6 +2695,11 @@
      * Force a new device unlock password (the password needed to access the entire device, not for
      * individual accounts) on the user. This takes effect immediately.
      * <p>
+     * <em>For device owner and profile owners targeting SDK level
+     * {@link android.os.Build.VERSION_CODES#O} or above, this API is no longer available and will
+     * throw {@link SecurityException}. Please use the new API {@link #resetPasswordWithToken}
+     * instead. </em>
+     * <p>
      * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
      * device admins that are not device owner and not profile owner.
      * The password can now only be changed if there is currently no password set.  Device owner
@@ -2740,6 +2746,127 @@
     }
 
     /**
+     * Called by a profile or device owner to provision a token which can later be used to reset the
+     * device lockscreen password (if called by device owner), or work challenge (if called by
+     * profile owner), via {@link #resetPasswordWithToken}.
+     * <p>
+     * If the user currently has a lockscreen password, the provisioned token will not be
+     * immediately usable; it only becomes active after the user performs a confirm credential
+     * operation, which can be triggered by {@link KeyguardManager#createConfirmDeviceCredentialIntent}.
+     * If the user has no lockscreen password, the token is activated immediately. In all cases,
+     * the active state of the current token can be checked by {@link #isResetPasswordTokenActive}.
+     * For security reasons, un-activated tokens are only stored in memory and will be lost once
+     * the device reboots. In this case a new token needs to be provisioned again.
+     * <p>
+     * Once provisioned and activated, the token will remain effective even if the user changes
+     * or clears the lockscreen password.
+     * <p>
+     * <em>This token is highly sensitive and should be treated at the same level as user
+     * credentials. In particular, NEVER store this token on device in plaintext, especially in
+     * Device-Encrypted storage if the token will be used to reset password on FBE devices before
+     * user unlocks.
+     * </em>
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param token a secure token a least 32-byte long, which must be generated by a
+     *        cryptographically strong random number generator.
+     * @return true if the operation is successful, false otherwise.
+     * @throws IllegalArgumentException if the supplied token is invalid.
+     * @throws SecurityException
+     */
+    public boolean setResetPasswordToken(ComponentName admin, byte[] token) {
+        throwIfParentInstance("setResetPasswordToken");
+        if (mService != null) {
+            try {
+                return mService.setResetPasswordToken(admin, token);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by a profile or device owner to revoke the current password reset token.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return true if the operation is successful, false otherwise.
+     */
+    public boolean clearResetPasswordToken(ComponentName admin) {
+        throwIfParentInstance("clearResetPasswordToken");
+        if (mService != null) {
+            try {
+                return mService.clearResetPasswordToken(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by a profile or device owner to check if the current reset password token is active.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return true if the token is active, false otherwise.
+     * @throws IllegalStateException if no token has been set.
+     */
+    public boolean isResetPasswordTokenActive(ComponentName admin) {
+        throwIfParentInstance("isResetPasswordTokenActive");
+        if (mService != null) {
+            try {
+                return mService.isResetPasswordTokenActive(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by device or profile owner to force set a new device unlock password or a work profile
+     * challenge on current user. This takes effect immediately.
+     * <p>
+     * Unlike {@link #resetPassword}, this API can change the password even before the user or
+     * device is unlocked or decrypted. The supplied token must have been previously provisioned via
+     * {@link #setResetPasswordToken}, and in active state {@link #isResetPasswordTokenActive}.
+     * <p>
+     * The given password must be sufficient for the current password quality and length constraints
+     * as returned by {@link #getPasswordQuality(ComponentName)} and
+     * {@link #getPasswordMinimumLength(ComponentName)}; if it does not meet these constraints, then
+     * it will be rejected and false returned. Note that the password may be a stronger quality
+     * (containing alphanumeric characters when the requested quality is only numeric), in which
+     * case the currently active quality will be increased to match.
+     * <p>
+     * Calling with a null or empty password will clear any existing PIN, pattern or password if the
+     * current password constraints allow it.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param password The new password for the user. Null or empty clears the password.
+     * @param token the password reset token previously provisioned by #setResetPasswordToken.
+     * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and
+     *            {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
+     * @return Returns true if the password was applied, or false if it is not acceptable for the
+     *         current constraints.
+     * @throws SecurityException if the calling application does not own an active administrator
+     *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
+     * @throws IllegalStateException if the provided token is not valid.
+     * @throws IllegalArgumentException if the password does not meet system requirements.
+     */
+    public boolean resetPasswordWithToken(@NonNull ComponentName admin, String password,
+            byte[] token, int flags) {
+        throwIfParentInstance("resetPassword");
+        if (mService != null) {
+            try {
+                return mService.resetPasswordWithToken(admin, password, token, flags);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by an application that is administering the device to set the maximum time for user
      * activity until the device will lock. This limits the length that the user can set. It takes
      * effect immediately.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 79fe10e..c2f75c8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -342,4 +342,9 @@
     long getLastSecurityLogRetrievalTime();
     long getLastBugReportRequestTime();
     long getLastNetworkLogRetrievalTime();
+
+    boolean setResetPasswordToken(in ComponentName admin, in byte[] token);
+    boolean clearResetPasswordToken(in ComponentName admin);
+    boolean isResetPasswordTokenActive(in ComponentName admin);
+    boolean resetPasswordWithToken(in ComponentName admin, String password, in byte[] token, int flags);
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index c8f6406..40deeae 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -37,6 +37,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.graphics.drawable.MaskableIconDrawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -803,7 +804,15 @@
             }
             try {
                 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
-                return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp);
+                if (bmp != null) {
+                    BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
+                    if (shortcut.hasMaskableBitmap()) {
+                        return new MaskableIconDrawable(null, dr);
+                    } else {
+                        return dr;
+                    }
+                }
+                return null;
             } finally {
                 try {
                     pfd.close();
@@ -821,7 +830,8 @@
                     return loadDrawableResourceFromPackage(shortcut.getPackage(),
                             icon.getResId(), shortcut.getUserHandle(), density);
                 }
-                case Icon.TYPE_BITMAP: {
+                case Icon.TYPE_BITMAP:
+                case Icon.TYPE_BITMAP_MASKABLE: {
                     return icon.loadDrawable(mContext);
                 }
                 default:
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index b4dcdf7..f1f2683 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -92,6 +92,9 @@
     public static final int FLAG_IMMUTABLE = 1 << 8;
 
     /** @hide */
+    public static final int FLAG_MASKABLE_BITMAP = 1 << 9;
+
+    /** @hide */
     @IntDef(flag = true,
             value = {
             FLAG_DYNAMIC,
@@ -103,6 +106,7 @@
             FLAG_DISABLED,
             FLAG_STRINGS_RESOLVED,
             FLAG_IMMUTABLE,
+            FLAG_MASKABLE_BITMAP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -690,6 +694,7 @@
         switch (icon.getType()) {
             case Icon.TYPE_RESOURCE:
             case Icon.TYPE_BITMAP:
+            case Icon.TYPE_BITMAP_MASKABLE:
                 break; // OK
             default:
                 throw getInvalidIconException();
@@ -815,8 +820,9 @@
          * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported
          * and will be ignored.
          *
-         * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)} and
-         * {@link Icon#createWithResource} are supported.
+         * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
+         * {@link Icon#createWithMaskableBitmap(Bitmap)}
+         * and {@link Icon#createWithResource} are supported.
          * Other types, such as URI-based icons, are not supported.
          *
          * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)
@@ -1442,6 +1448,15 @@
     }
 
     /**
+     * Return whether a shortcut's icon is maskable.
+     *
+     * @hide internal/unit tests only
+     */
+    public boolean hasMaskableBitmap() {
+        return hasFlags(FLAG_MASKABLE_BITMAP);
+    }
+
+    /**
      * Return whether a shortcut only contains "key" information only or not.  If true, only the
      * following fields are available.
      * <ul>
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index e5f0bf0..31a74dc 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.Objects;
 
@@ -41,6 +42,8 @@
 // etc.) so that clients can pull out these details depending on the type of network.
 public class NetworkKey implements Parcelable {
 
+    private static final String TAG = "NetworkKey";
+
     /** A wifi network, for which {@link #wifiKey} will be populated. */
     public static final int TYPE_WIFI = 1;
 
@@ -59,13 +62,28 @@
     /**
      * Constructs a new NetworkKey for the given wifi {@link ScanResult}.
      *
-     * @throws IllegalArgumentException if the given ScanResult is malformed
+     * @return  A new {@link NetworkKey} instance or <code>null</code> if the given
+     *          {@link ScanResult} instance is malformed.
      * @hide
      */
-    public static NetworkKey createFromScanResult(ScanResult result) {
-        return new NetworkKey(
-                new WifiKey(
-                        '"' + result.wifiSsid.toString() + '"', result.BSSID));
+    @Nullable
+    public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
+        if (result != null && result.wifiSsid != null) {
+            final String ssid = result.wifiSsid.toString();
+            final String bssid = result.BSSID;
+            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
+                    && !TextUtils.isEmpty(bssid)) {
+                WifiKey wifiKey;
+                try {
+                    wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Unable to create WifiKey.", e);
+                    return null;
+                }
+                return new NetworkKey(wifiKey);
+            }
+        }
+        return null;
     }
 
     /**
@@ -83,7 +101,14 @@
             final String bssid = wifiInfo.getBSSID();
             if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
                     && !TextUtils.isEmpty(bssid)) {
-                return new NetworkKey(new WifiKey(ssid, bssid));
+                WifiKey wifiKey;
+                try {
+                    wifiKey = new WifiKey(ssid, bssid);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Unable to create WifiKey.", e);
+                    return null;
+                }
+                return new NetworkKey(wifiKey);
             }
         }
         return null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2dfba28..9ecc6389 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6628,6 +6628,14 @@
                 "lock_screen_show_notifications";
 
         /**
+         * This preference stores the last stack active task time for each user, which affects what
+         * tasks will be visible in Overview.
+         * @hide
+         */
+        public static final String OVERVIEW_LAST_STACK_ACTIVE_TIME =
+                "overview_last_stack_active_time";
+
+        /**
          * List of TV inputs that are currently hidden. This is a string
          * containing the IDs of all hidden TV inputs. Each ID is encoded by
          * {@link android.net.Uri#encode(String)} and separated by ':'.
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index fcb4c7b..3d012bf 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -109,6 +109,10 @@
     // background while in data-usage save mode, as read from the configuration files.
     final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
 
+    // These are the packages that are white-listed to be able to run background location
+    // without throttling, as read from the configuration files.
+    final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>();
+
     // These are the action strings of broadcasts which are whitelisted to
     // be delivered anonymously even to apps which target O+.
     final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
@@ -182,6 +186,10 @@
         return mAllowInDataUsageSave;
     }
 
+    public ArraySet<String> getAllowUnthrottledLocation() {
+        return mAllowUnthrottledLocation;
+    }
+
     public ArraySet<String> getLinkedApps() {
         return mLinkedApps;
     }
@@ -446,6 +454,17 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
+                } else if ("allow-unthrottled-location".equals(name) && allowAll) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<allow-unthrottled-location> without package in "
+                            + permFile + " at " + parser.getPositionDescription());
+                    } else {
+                        mAllowUnthrottledLocation.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
                 } else if ("allow-implicit-broadcast".equals(name) && allowAll) {
                     String action = parser.getAttributeValue(null, "action");
                     if (action == null) {
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index 1afe9da..fff23a0 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -4,6 +4,7 @@
 import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.when;
 
+import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiSsid;
 import android.support.test.runner.AndroidJUnit4;
@@ -17,7 +18,9 @@
 @RunWith(AndroidJUnit4.class)
 public class NetworkKeyTest {
     private static final String VALID_SSID = "\"ssid1\"";
+    private static final String VALID_UNQUOTED_SSID = "ssid1";
     private static final String VALID_BSSID = "00:00:00:00:00:00";
+    private static final String INVALID_BSSID = "invalid_bssid";
     @Mock private WifiInfo mWifiInfo;
 
     @Before
@@ -64,6 +67,13 @@
     }
 
     @Test
+    public void createFromWifi_invalidBssid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
+        when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID);
+        assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+    }
+
+    @Test
     public void createFromWifi_validWifiInfo() throws Exception {
         when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
         when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
@@ -72,4 +82,72 @@
         final NetworkKey actual = NetworkKey.createFromWifiInfo(mWifiInfo);
         assertEquals(expected, actual);
     }
+
+    @Test
+    public void createFromScanResult_nullInput() {
+        assertNull(NetworkKey.createFromScanResult(null));
+    }
+
+    @Test
+    public void createFromScanResult_nullWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.BSSID = VALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_emptyWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded("");
+        scanResult.BSSID = VALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_noneWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(WifiSsid.NONE);
+        scanResult.BSSID = VALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_nullBssid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_emptyBssid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.BSSID = "";
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_invalidBssid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.BSSID = INVALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_validWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.BSSID = VALID_BSSID;
+
+        NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID));
+        NetworkKey actual = NetworkKey.createFromScanResult(scanResult);
+        assertEquals(expected, actual);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 0ec16ae2..9ac4d2d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -510,7 +510,7 @@
                 }
 
                 NetworkKey key = NetworkKey.createFromScanResult(result);
-                if (!mRequestedScores.contains(key)) {
+                if (key != null && !mRequestedScores.contains(key)) {
                     scoresToRequest.add(key);
                 }
 
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
index 9c3bd3a..64bbff0 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver.xml
@@ -23,7 +23,7 @@
         android:fillColor="#FFFFFFFF"
         android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#54FFFFFF"
         android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
index 918c61c..3001ad9 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
@@ -20,9 +20,9 @@
         android:viewportHeight="24.0"
         android:tint="?android:attr/colorControlNormal">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/>
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index d6abc47..acae9f5 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -25,5 +25,5 @@
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
         android:textColor="?android:attr/textColorPrimary"
         android:gravity="center_vertical|start"
-        android:paddingEnd="4dp"
+        android:paddingStart="4dp"
         />
diff --git a/packages/SystemUI/res/layout/divider.xml b/packages/SystemUI/res/layout/divider.xml
index 9581437..f1f0df0 100644
--- a/packages/SystemUI/res/layout/divider.xml
+++ b/packages/SystemUI/res/layout/divider.xml
@@ -16,5 +16,6 @@
 <View xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="72dp"
     android:layout_height="1dp"
+    android:layout_marginTop="8dp"
     android:background="?android:attr/colorForeground"
     android:alpha="?android:attr/disabledAlpha" />
diff --git a/packages/SystemUI/res/layout/qs_page_indicator.xml b/packages/SystemUI/res/layout/qs_page_indicator.xml
index 02bd31a..583753a 100644
--- a/packages/SystemUI/res/layout/qs_page_indicator.xml
+++ b/packages/SystemUI/res/layout/qs_page_indicator.xml
@@ -20,9 +20,8 @@
     android:layout_width="match_parent"
     android:layout_height="48dp"
     android:layout_gravity="center"
-    android:layout_marginTop="40dp"
     android:layout_marginBottom="24dp"
     android:focusable="true"
     android:gravity="center"
     android:importantForAccessibility="yes"
-    android:visibility="gone"/>
\ No newline at end of file
+    android:visibility="gone"/>
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 8ff1d1e..00427cb 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingBottom="24dp"
     android:clipChildren="false"
     android:clipToPadding="false">
 
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index a093b87..8d1f9e4 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -16,10 +16,12 @@
 -->
 <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        android:paddingTop="16dp">
+        android:gravity="center_horizontal"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp">
      <TextView android:id="@+id/tile_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 6988c76..080f553 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -17,7 +17,6 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_height="48dp"
     android:layout_width="match_parent"
-    android:layout_marginBottom="24dp"
     android:paddingLeft="16dp"
     android:paddingRight="16dp"
     style="@style/BrightnessDialogContainer">
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 3e8e72a..78d4bdd 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -85,16 +85,6 @@
 
                 <include layout="@layout/system_icons" />
             </FrameLayout>
-
-            <TextView
-                android:id="@+id/battery_level"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginStart="@dimen/header_battery_margin_expanded"
-                android:importantForAccessibility="noHideDescendants"
-                android:textColor="?android:attr/textColorPrimary"
-                android:textSize="@dimen/battery_level_text_size"/>
         </LinearLayout>
 
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2102e07..40d4d6f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -219,8 +219,8 @@
     <!-- The size of the gesture span needed to activate the "pull" notification expansion -->
     <dimen name="pull_span_min">25dp</dimen>
 
-    <dimen name="qs_tile_height">80dp</dimen>
-    <dimen name="qs_tile_margin">36dp</dimen>
+    <dimen name="qs_tile_height">88dp</dimen>
+    <dimen name="qs_tile_margin">28dp</dimen>
     <dimen name="qs_tile_margin_top">16dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 77de9a2..b825cfb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1725,6 +1725,10 @@
         not appear on production builds ever. -->
     <string name="tuner_doze" translatable="false">Ambient Display</string>
 
+    <!-- Ambient display, Sensors wake up device of the tuner. Non-translatable since it should
+        not appear on production builds ever. -->
+    <string name="tuner_doze_sensors_wake_up_fully" translatable="false">Wake up device on double tap or lift</string>
+
     <!-- Ambient display always-on of the tuner. Non-translatable since it should
         not appear on production builds ever. -->
     <string name="tuner_doze_always_on" translatable="false">Always on</string>
@@ -1741,18 +1745,6 @@
     <!-- Label for PIP the drag to close zone [CHAR LIMIT=NONE]-->
     <string name="pip_phone_close">Close</string>
 
-    <!-- PIP section of the tuner. Non-translatable since it should
-        not appear on production builds ever. -->
-    <string name="picture_in_picture" translatable="false">Picture-in-Picture</string>
-
-    <!-- PIP drag to dismiss title. Non-translatable since it should
-        not appear on production builds ever. -->
-    <string name="pip_drag_to_dismiss_title" translatable="false">Drag to dismiss</string>
-
-    <!-- PIP drag to dismiss description. Non-translatable since it should
-        not appear on production builds ever. -->
-    <string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string>
-
     <!-- Tuner string -->
     <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
     <!-- Tuner string -->
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index c354811..85f12b5 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -123,18 +123,6 @@
 
     <!--
     <PreferenceScreen
-      android:key="picture_in_picture"
-      android:title="@string/picture_in_picture">
-
-        <com.android.systemui.tuner.TunerSwitch
-          android:key="pip_drag_to_dismiss"
-          android:title="@string/pip_drag_to_dismiss_title"
-          android:summary="@string/pip_drag_to_dismiss_summary"
-          sysui:defValue="false" />
-
-    </PreferenceScreen>
-
-    <PreferenceScreen
       android:key="doze"
       android:title="@string/tuner_doze">
 
@@ -143,6 +131,11 @@
           android:title="@string/tuner_doze_always_on"
           sysui:defValue="false" />
 
+        <com.android.systemui.tuner.TunerSwitch
+          android:key="doze_sensors_wake_up_fully"
+          android:title="@string/tuner_doze_sensors_wake_up_fully"
+          sysui:defValue="false" />
+
     </PreferenceScreen>
     -->
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 80d4a26..1f58d4c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -595,6 +595,10 @@
         }
     }
 
+    public boolean isScreenOn() {
+        return mScreenOn;
+    }
+
     static class DisplayClientState {
         public int clientGeneration;
         public boolean clearing;
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index f821308..bda4c95 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -65,6 +65,7 @@
     private SettingObserver mSettingObserver;
     private int mTextColor;
     private int mLevel;
+    private boolean mForceShowPercent;
 
     public BatteryMeterView(Context context) {
         this(context, null, 0);
@@ -103,6 +104,11 @@
         updateShowPercent();
     }
 
+    public void forceShowPercent() {
+        mForceShowPercent = true;
+        updateShowPercent();
+    }
+
     // StatusBarIconController reaches in here and adjusts the layout parameters of the icon
     public ImageView getBatteryIconView() {
         return mBatteryIconView;
@@ -173,13 +179,12 @@
     private void updateShowPercent() {
         final boolean showing = mBatteryPercentView != null;
         if (0 != Settings.System.getInt(getContext().getContentResolver(),
-                BatteryMeterView.SHOW_PERCENT_SETTING, 0)) {
+                BatteryMeterView.SHOW_PERCENT_SETTING, 0) || mForceShowPercent) {
             if (!showing) {
                 mBatteryPercentView = loadPercentView();
                 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
                 updatePercentText();
                 addView(mBatteryPercentView,
-                        0,
                         new ViewGroup.LayoutParams(
                                 LayoutParams.WRAP_CONTENT,
                                 LayoutParams.MATCH_PARENT));
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 19ae295..b9ae585 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -49,6 +49,7 @@
         Key.QS_WORK_ADDED,
     })
     public @interface Key {
+        @Deprecated
         String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime";
         String DEBUG_MODE_ENABLED = "debugModeEnabled";
         String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 7c15096..b3a0eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -91,8 +91,7 @@
             @Override
             public void requestState(DozeProvider.DozeState state) {
                 if (state == DozeProvider.DozeState.WAKE_UP) {
-                    PowerManager pm = context.getSystemService(PowerManager.class);
-                    pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
+                    machine.wakeUp();
                     return;
                 }
                 machine.requestState(implState(state));
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 6a868d5..c9eb790 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -158,6 +158,11 @@
         return mState;
     }
 
+    /** Requests the PowerManager to wake up now. */
+    public void wakeUp() {
+        mDozeService.requestWakeUp();
+    }
+
     private boolean isExecutingTransition() {
         return !mQueuedRequests.isEmpty();
     }
@@ -300,5 +305,8 @@
 
         /** Request a display state. See {@link android.view.Display#STATE_DOZE}. */
         void setDozeScreenState(int state);
+
+        /** Request waking up. */
+        void requestWakeUp();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 6186df1..e55a597 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.doze;
 
+import android.os.PowerManager;
+import android.os.SystemClock;
 import android.service.dreams.DreamService;
 import android.util.Log;
 
@@ -72,4 +74,10 @@
             mDozeMachine.dump(pw);
         }
     }
+
+    @Override
+    public void requestWakeUp() {
+        PowerManager pm = getSystemService(PowerManager.class);
+        pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index db5a392..b5c7dd3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -97,7 +97,11 @@
     }
 
     private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) {
-        requestPulse(pulseReason, sensorPerformedProxCheck);
+        if (mDozeParameters.getSensorsWakeUpFully()) {
+            mMachine.wakeUp();
+        } else {
+            requestPulse(pulseReason, sensorPerformedProxCheck);
+        }
 
         if (pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP) {
             final long timeSinceNotification =
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index e8c0050..d832810 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -37,9 +37,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.FlingAnimationUtils;
-import com.android.systemui.tuner.TunerService;
 
 import java.io.PrintWriter;
 
@@ -47,17 +45,18 @@
  * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
  * the PIP.
  */
-public class PipTouchHandler implements TunerService.Tunable {
+public class PipTouchHandler {
     private static final String TAG = "PipTouchHandler";
 
     // These values are used for metrics and should never change
     private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
     private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1;
 
-    private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss";
-
     private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 200;
 
+    // Allow dragging the PIP to a location to close it
+    private static final boolean ENABLE_DRAG_TO_DISMISS = false;
+
     private final Context mContext;
     private final IActivityManager mActivityManager;
     private final IWindowManager mWindowManager;
@@ -70,9 +69,6 @@
     private final PipDismissViewController mDismissViewController;
     private final PipSnapAlgorithm mSnapAlgorithm;
 
-    // Allow dragging the PIP to a location to close it
-    private boolean mEnableDragToDismiss = false;
-
     // The current movement bounds
     private Rect mMovementBounds = new Rect();
 
@@ -86,7 +82,7 @@
     private Runnable mShowDismissAffordance = new Runnable() {
         @Override
         public void run() {
-            if (mEnableDragToDismiss) {
+            if (ENABLE_DRAG_TO_DISMISS) {
                 mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
             }
         }
@@ -183,23 +179,6 @@
         mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
                 mFlingAnimationUtils);
         registerInputConsumer();
-
-        // Register any tuner settings changes
-        Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_DRAG_TO_DISMISS);
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (newValue == null) {
-            // Reset back to default
-            mEnableDragToDismiss = false;
-            return;
-        }
-        switch (key) {
-            case TUNER_KEY_DRAG_TO_DISMISS:
-                mEnableDragToDismiss = Integer.parseInt(newValue) != 0;
-                break;
-        }
     }
 
     public void onActivityPinned() {
@@ -439,7 +418,7 @@
 
         @Override
         public void onDown(PipTouchState touchState) {
-            if (mEnableDragToDismiss) {
+            if (ENABLE_DRAG_TO_DISMISS) {
                 mDismissViewController.createDismissTarget();
                 mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY);
             }
@@ -451,7 +430,7 @@
                 mSavedSnapFraction = -1f;
             }
 
-            if (touchState.startedDragging() && mEnableDragToDismiss) {
+            if (touchState.startedDragging() && ENABLE_DRAG_TO_DISMISS) {
                 mHandler.removeCallbacks(mShowDismissAffordance);
                 mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
             }
@@ -469,7 +448,7 @@
                 mTmpBounds.offsetTo((int) left, (int) top);
                 mMotionHelper.movePip(mTmpBounds);
 
-                if (mEnableDragToDismiss) {
+                if (ENABLE_DRAG_TO_DISMISS) {
                     mDismissViewController.updateDismissTarget(mTmpBounds);
                 }
                 return true;
@@ -480,7 +459,7 @@
         @Override
         public boolean onUp(PipTouchState touchState) {
             try {
-                if (mEnableDragToDismiss) {
+                if (ENABLE_DRAG_TO_DISMISS) {
                     mHandler.removeCallbacks(mShowDismissAffordance);
                     PointF vel = mTouchState.getVelocity();
                     final float velocity = PointF.length(vel.x, vel.y);
@@ -583,7 +562,7 @@
         pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
         pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
         pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
-        pw.println(innerPrefix + "mEnableDragToDismiss=" + mEnableDragToDismiss);
+        pw.println(innerPrefix + "mEnableDragToDismiss=" + ENABLE_DRAG_TO_DISMISS);
         mSnapAlgorithm.dump(pw, innerPrefix);
         mTouchState.dump(pw, innerPrefix);
         mMotionHelper.dump(pw, innerPrefix);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index a231e79..3559257 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -242,7 +242,7 @@
                 maxHeight = height;
             }
         }
-        setMeasuredDimension(getMeasuredWidth(), maxHeight);
+        setMeasuredDimension(getMeasuredWidth(), maxHeight + getPaddingBottom());
     }
 
     private final Runnable mDistribute = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index c85f83b..e0d1cba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -160,7 +160,9 @@
         mAllViews.clear();
         mTopFiveQs.clear();
 
-        mAllViews.add((View) mQsPanel.getTileLayout());
+        QSTileLayout tileLayout = mQsPanel.getTileLayout();
+        mAllViews.add((View) tileLayout);
+        firstPageBuilder.addFloat(tileLayout, "translationY", mQsPanel.getHeight(), 0);
 
         for (QSTile<?> tile : tiles) {
             QSTileBaseView tileView = mQsPanel.getTileView(tile);
@@ -168,7 +170,6 @@
                 Log.e(TAG, "tileView is null " + tile.getTileSpec());
                 continue;
             }
-            final TextView label = ((QSTileView) tileView).getLabel();
             final View tileIcon = tileView.getIcon().getIconView();
             View view = mQs.getView();
             if (count < mNumQuickTiles && mAllowFancy) {
@@ -187,12 +188,12 @@
 
                 // Counteract the parent translation on the tile. So we have a static base to
                 // animate the label position off from.
-                firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+                //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
 
-                // Move the real tile's label from the quick tile position to its final
+                // Move the real tile from the quick tile position to its final
                 // location.
-                translationXBuilder.addFloat(label, "translationX", -xDiff, 0);
-                translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+                translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
+                translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
 
                 mTopFiveQs.add(tileView.getIcon());
                 mAllViews.add(tileView.getIcon());
@@ -209,22 +210,22 @@
 
                 firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
                 translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
-                translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+                translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
                 translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
 
                 mAllViews.add(tileIcon);
             } else {
                 firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
+                firstPageBuilder.addFloat(tileView, "translationY", -mQsPanel.getHeight(), 0);
             }
             mAllViews.add(tileView);
-            mAllViews.add(label);
             count++;
         }
         if (mAllowFancy) {
             // Make brightness appear static position and alpha in through second half.
             View brightness = mQsPanel.getBrightnessView();
             if (brightness != null) {
-//                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
+                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
                 mBrightnessAnimator = new TouchAnimator.Builder()
                         .addFloat(brightness, "alpha", 0, 1)
                         .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
@@ -240,7 +241,7 @@
             // Fade in the tiles/labels as we reach the final position.
             mFirstPageDelayedAnimator = new TouchAnimator.Builder()
                     .setStartDelay(EXPANDED_TILE_DELAY)
-                    .addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1)
+                    .addFloat(tileLayout, "alpha", 0, 1)
                     .addFloat(mQsPanel.getFooter().getView(), "alpha", 0, 1).build();
             mAllViews.add(mQsPanel.getFooter().getView());
             float px = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 1569b0c..e8d5ece 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -441,8 +441,15 @@
         }
         r.tile.setDetailListening(show);
         int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
-        int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2
-                + getTop();
+        int y;
+        if (r.tileView instanceof QSTileView) {
+            View labelContainer = (View) ((QSTileView) r.tileView).getLabel().getParent();
+            y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + getTop()
+                    + labelContainer.getTop() + labelContainer.getHeight() / 2;
+        } else {
+            y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2
+                    + getTop();
+        }
         handleShowDetailImpl(r, show, x, y);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 0e04d0a..c750fdc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -15,38 +15,30 @@
  */
 package com.android.systemui.qs;
 
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.service.quicksettings.Tile;
 import android.text.TextUtils;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
 import android.widget.LinearLayout;
 import android.widget.Switch;
 
-import com.android.settingslib.Utils;
-
 import com.android.systemui.R;
 
 public class QSTileBaseView extends LinearLayout {
 
     private static final String TAG = "QSTileBaseView";
     private final H mHandler = new H();
+    private final FrameLayout mIconFrame;
     protected QSIconView mIcon;
     protected RippleDrawable mRipple;
     private Drawable mTileBackground;
@@ -63,15 +55,15 @@
         // Default to Quick Tile padding, and QSTileView will specify its own padding.
         int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
 
-        FrameLayout frame = new FrameLayout(context);
-        frame.setForegroundGravity(Gravity.CENTER);
+        mIconFrame = new FrameLayout(context);
+        mIconFrame.setForegroundGravity(Gravity.CENTER);
         int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
-        addView(frame, new LayoutParams(size, size));
+        addView(mIconFrame, new LayoutParams(size, size));
         mIcon = icon;
         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
         params.setMargins(0, padding, 0, padding);
-        frame.addView(mIcon, params);
+        mIconFrame.addView(mIcon, params);
 
         mTileBackground = newTileBackground();
         if (mTileBackground instanceof RippleDrawable) {
@@ -105,7 +97,7 @@
     private void updateRippleSize(int width, int height) {
         // center the touch feedback on the center of the icon, and dial it down a bit
         final int cx = width / 2;
-        final int cy = height / 2;
+        final int cy = mIconFrame.getMeasuredHeight() / 2;
         final int rad = (int) (mIcon.getHeight() * .85f);
         mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 232941d..428fe9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.drawable.RippleDrawable;
 import android.service.quicksettings.Tile;
 import android.text.SpannableStringBuilder;
 import android.text.style.ForegroundColorSpan;
@@ -28,6 +29,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -43,8 +45,7 @@
     protected TextView mLabel;
     private ImageView mPadLock;
     private int mState;
-    private OnClickListener mClick;
-    private OnClickListener mSecondaryClick;
+    private ViewGroup mLabelContainer;
 
     public QSTileView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -76,13 +77,15 @@
     }
 
     protected void createLabel() {
-        ViewGroup view = (ViewGroup) LayoutInflater.from(getContext())
-                .inflate(R.layout.qs_tile_label, null);
-        view.setClipChildren(false);
-        view.setClipToPadding(false);
-        mLabel = (TextView) view.findViewById(R.id.tile_label);
-        mPadLock = (ImageView) view.findViewById(R.id.restricted_padlock);
-        addView(view);
+        mLabelContainer = (ViewGroup) LayoutInflater.from(getContext())
+                .inflate(R.layout.qs_tile_label, this, false);
+        mLabelContainer.setClipChildren(false);
+        mLabelContainer.setClipToPadding(false);
+        mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label);
+        mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock);
+
+        mLabelContainer.setBackground(newTileBackground());
+        addView(mLabelContainer);
     }
 
     @Override
@@ -104,17 +107,10 @@
     }
 
     @Override
-    public void init(OnClickListener click, OnClickListener secondaryClick, OnLongClickListener longClick) {
-        mClick = click;
-        mSecondaryClick = secondaryClick;
+    public void init(OnClickListener click, OnClickListener secondaryClick,
+            OnLongClickListener longClick) {
         super.init(click, secondaryClick, longClick);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (event.getActionMasked() == MotionEvent.ACTION_UP)  {
-            setOnClickListener(event.getY() < (getMeasuredHeight() / 2) ? mClick : mSecondaryClick);
-        }
-        return super.onTouchEvent(event);
+        mLabelContainer.setClickable(true);
+        mLabelContainer.setOnClickListener(secondaryClick);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 8227f8f..f7bfc1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -104,11 +104,6 @@
     }
 
     @Override
-    protected void handleSecondaryClick() {
-        showDetail(true);
-    }
-
-    @Override
     public CharSequence getTileLabel() {
         return mContext.getString(R.string.battery);
     }
@@ -118,7 +113,6 @@
         int level = (arg != null) ? (Integer) arg : mLevel;
         String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
 
-        state.dualTarget = true;
         state.state = mCharging ? Tile.STATE_UNAVAILABLE
                 : mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index b48b829..3c28f76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -123,7 +123,6 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        state.dualTarget = true;
         state.label = mContext.getString(R.string.quick_settings_cast_title);
         state.contentDescription = state.label;
         state.value = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index a6fe0ea..c9debb2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -31,6 +31,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
@@ -44,7 +45,6 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Interpolators;
 import com.android.keyguard.LatencyTracker;
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
@@ -181,8 +181,10 @@
                 // is still valid.  Otherwise, we need to reset the lastStackactiveTime to the
                 // currentTime and remove the old tasks in between which would not be previously
                 // visible, but currently would be in the new currentTime
-                long oldLastStackActiveTime = Prefs.getLong(RecentsActivity.this,
-                        Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
+                int currentUser = SystemServicesProxy.getInstance(RecentsActivity.this)
+                        .getCurrentUser();
+                long oldLastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(),
+                        Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1, currentUser);
                 if (oldLastStackActiveTime != -1) {
                     long currentTime = System.currentTimeMillis();
                     if (currentTime < oldLastStackActiveTime) {
@@ -200,8 +202,8 @@
                                 Recents.getSystemServices().removeTask(task.persistentId);
                             }
                         }
-                        Prefs.putLong(RecentsActivity.this,
-                                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, currentTime);
+                        Settings.Secure.putLongForUser(RecentsActivity.this.getContentResolver(),
+                                Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, currentTime, currentUser);
                     }
                 }
             }
@@ -834,8 +836,9 @@
         Recents.getTaskLoader().dump(prefix, writer);
 
         String id = Integer.toHexString(System.identityHashCode(this));
-        long lastStackActiveTime = Prefs.getLong(this,
-                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
+        long lastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(),
+                Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1,
+                SystemServicesProxy.getInstance(this).getCurrentUser());
 
         writer.print(prefix); writer.print(TAG);
         writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 11b5984..12c10df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -26,6 +26,8 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.util.ArraySet;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -130,6 +132,7 @@
             preloadRawTasks(includeFrontMostExcludedTask);
         }
 
+        SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext);
         SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
         SparseIntArray affiliatedTaskCounts = new SparseIntArray();
         SparseBooleanArray lockedUsers = new SparseBooleanArray();
@@ -137,8 +140,10 @@
                 R.string.accessibility_recents_item_will_be_dismissed);
         String appInfoDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_open_app_info);
-        long lastStackActiveTime = Prefs.getLong(mContext,
-                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
+        int currentUserId = ssp.getCurrentUser();
+        long legacyLastStackActiveTime = migrateLegacyLastStackActiveTime(currentUserId);
+        long lastStackActiveTime = Settings.Secure.getLongForUser(mContext.getContentResolver(),
+                Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, currentUserId);
         if (RecentsDebugFlags.Static.EnableMockTasks) {
             lastStackActiveTime = 0;
         }
@@ -205,8 +210,8 @@
             affiliatedTasks.put(taskKey.id, taskKey);
         }
         if (newLastStackActiveTime != -1) {
-            Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
-                    newLastStackActiveTime);
+            Settings.Secure.putLongForUser(mContext.getContentResolver(),
+                    Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, newLastStackActiveTime, currentUserId);
         }
 
         // Initialize the stacks
@@ -285,4 +290,36 @@
     private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) {
         return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME);
     }
+
+
+    /**
+     * Migrate the last active time from the prefs to the secure settings.
+     *
+     * The first time this runs, it will:
+     * 1) fetch the last stack active time from the prefs
+     * 2) set the prefs to the last stack active time for all users
+     * 3) clear the pref
+     * 4) return the last stack active time
+     *
+     * Subsequent calls to this will return zero.
+     */
+    private long migrateLegacyLastStackActiveTime(int currentUserId) {
+        long legacyLastStackActiveTime = Prefs.getLong(mContext,
+                Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1);
+        if (legacyLastStackActiveTime != -1) {
+            Prefs.remove(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME);
+            UserManager userMgr = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            List<UserInfo> users = userMgr.getUsers();
+            for (int i = 0; i < users.size(); i++) {
+                int userId = users.get(i).id;
+                if (userId != currentUserId) {
+                    Settings.Secure.putLongForUser(mContext.getContentResolver(),
+                            Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime,
+                            userId);
+                }
+            }
+            return legacyLastStackActiveTime;
+        }
+        return 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index d599ec1..bc992d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -87,6 +87,7 @@
     private KeyguardUpdateMonitorCallback mUpdateMonitor;
 
     private final DevicePolicyManager mDevicePolicyManager;
+    private boolean mDozing;
 
     public KeyguardIndicationController(Context context, ViewGroup indicationArea,
             LockIcon lockIcon) {
@@ -139,7 +140,7 @@
             return;
         }
 
-        if (mDevicePolicyManager.isDeviceManaged()) {
+        if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
             final CharSequence organizationName =
                     mDevicePolicyManager.getDeviceOwnerOrganizationName();
             if (organizationName != null) {
@@ -224,6 +225,18 @@
         if (mVisible) {
             // Walk down a precedence-ordered list of what should indication
             // should be shown based on user or device state
+            if (mDozing) {
+                // If we're dozing, never show a persistent indication.
+                if (!TextUtils.isEmpty(mTransientIndication)) {
+                    mTextView.switchIndication(mTransientIndication);
+                    mTextView.setTextColor(mTransientTextColor);
+
+                } else {
+                    mTextView.switchIndication(null);
+                }
+                return;
+            }
+
             if (!mUserManager.isUserUnlocked(ActivityManager.getCurrentUser())) {
                 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
                 mTextView.setTextColor(Color.WHITE);
@@ -319,6 +332,12 @@
         }
     };
 
+    public void setDozing(boolean dozing) {
+        mDozing = dozing;
+        updateIndication();
+        updateDisclosure();
+    }
+
     protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
         private int mLastSuccessiveErrorMessage = -1;
 
@@ -349,7 +368,8 @@
             int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor);
-            } else if (updateMonitor.isDeviceInteractive()) {
+            } else if (updateMonitor.isDeviceInteractive()
+                    || mDozing && updateMonitor.isScreenOn()) {
                 mLockIcon.setTransientFpError(true);
                 showTransientIndication(helpString, errorColor);
                 mHandler.removeMessages(MSG_CLEAR_FP_MSG);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 0e074c7..883a66b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -31,6 +31,7 @@
 
 public class DozeParameters {
     private static final int MAX_DURATION = 60 * 1000;
+    public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
 
     private final Context mContext;
 
@@ -56,6 +57,10 @@
         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
         pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
                 dumpPickupSubtypePerformsProxCheck());
+        if (Build.IS_DEBUGGABLE) {
+            pw.print("    getAlwaysOn(): "); pw.println(getAlwaysOn());
+            pw.print("    getSensorsWakeUpFully(): "); pw.println(getSensorsWakeUpFully());
+        }
     }
 
     private String dumpPickupSubtypePerformsProxCheck() {
@@ -118,6 +123,12 @@
                 Settings.Secure.DOZE_ALWAYS_ON, 0, UserHandle.USER_CURRENT) != 0;
     }
 
+    public boolean getSensorsWakeUpFully() {
+        return Build.IS_DEBUGGABLE
+                && Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                DOZE_SENSORS_WAKE_UP_FULLY, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
     private boolean getBoolean(String propName, int resId) {
         return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 2b335f4..8f63d45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -167,6 +167,7 @@
     private IntentButton mLeftPlugin;
     private String mLeftButtonStr;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
+    private boolean mDozing;
 
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
@@ -361,7 +362,7 @@
             // Things are not set up yet; reply hazy, ask again later
             return;
         }
-        mRightAffordanceView.setVisibility(mRightButton.getIcon().isVisible
+        mRightAffordanceView.setVisibility(!mDozing && mRightButton.getIcon().isVisible
                 ? View.VISIBLE : View.GONE);
     }
 
@@ -375,7 +376,7 @@
 
     private void updateLeftAffordanceIcon() {
         IconState state = mLeftButton.getIcon();
-        mLeftAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE);
+        mLeftAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE);
         mLeftAffordanceView.setImageDrawable(state.drawable, state.tint);
         mLeftAffordanceView.setContentDescription(state.contentDescription);
     }
@@ -846,6 +847,22 @@
         }
     };
 
+    public void setDozing(boolean dozing, boolean animate) {
+        mDozing = dozing;
+
+        updateCameraVisibility();
+        updateLeftAffordanceIcon();
+
+        if (dozing) {
+            mLockIcon.setVisibility(INVISIBLE);
+        } else {
+            mLockIcon.setVisibility(VISIBLE);
+            if (animate) {
+                startFinishDozeAnimation();
+            }
+        }
+    }
+
     private class DefaultLeftButton implements IntentButton {
 
         private IconState mIconState = new IconState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 5da3a10..6da9e90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1151,9 +1151,7 @@
                     .start();
         } else if (statusBarState == StatusBarState.KEYGUARD
                 || statusBarState == StatusBarState.SHADE_LOCKED) {
-            if (!mDozing) {
-                mKeyguardBottomArea.setVisibility(View.VISIBLE);
-            }
+            mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardBottomArea.setAlpha(1f);
         } else {
             mKeyguardBottomArea.setVisibility(View.GONE);
@@ -2103,13 +2101,12 @@
     private void updateDozingVisibilities(boolean animate) {
         if (mDozing) {
             mKeyguardStatusBar.setVisibility(View.INVISIBLE);
-            mKeyguardBottomArea.setVisibility(View.INVISIBLE);
+            mKeyguardBottomArea.setDozing(mDozing, animate);
         } else {
-            mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardStatusBar.setVisibility(View.VISIBLE);
+            mKeyguardBottomArea.setDozing(mDozing, animate);
             if (animate) {
                 animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION);
-                mKeyguardBottomArea.startFinishDozeAnimation();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 457ed6c..ade1b0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -26,7 +26,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
-import android.icu.text.NumberFormat;
 import android.os.UserManager;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
@@ -55,7 +54,6 @@
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.statusbar.SignalClusterView;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
@@ -68,7 +66,7 @@
 
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
         NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
-        BatteryStateChangeCallback, SignalCallback {
+        SignalCallback {
     private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
 
     private ActivityStarter mActivityStarter;
@@ -110,7 +108,6 @@
 
     private boolean mShowFullAlarm;
     private float mDateTimeTranslation;
-    private TextView mBatteryLevel;
     private SparseBooleanArray mRoamingsBySubId = new SparseBooleanArray();
     private boolean mIsRoaming;
 
@@ -161,8 +158,6 @@
         mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
         mAlarmStatus.setOnClickListener(this);
 
-        mBatteryLevel = (TextView) findViewById(R.id.battery_level);
-
         mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
         mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher);
@@ -179,7 +174,9 @@
         int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
         float intensity = colorForeground == Color.WHITE ? 0 : 1;
         cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground);
+
         BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
+        battery.forceShowPercent();
         int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
         battery.setRawColors(colorForeground, colorSecondary);
 
@@ -443,17 +440,6 @@
         }
     }
 
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
-        mBatteryLevel.setText(percentage);
-    }
-
-    @Override
-    public void onPowerSaveChanged(boolean isPowerSave) {
-        // Don't care.
-    }
-
     public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
             int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
             String description, boolean isWide, int subId, boolean roaming) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index cfbcf8c..3d6e4b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4322,6 +4322,7 @@
         mNotificationPanel.setDozing(mDozing, animate);
         mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
         mScrimController.setDozing(mDozing);
+        mKeyguardIndicationController.setDozing(mDozing);
 
         // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
         // for pulsing so the Keyguard fade-out animation scrim can take over.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index c3948258..32afee9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -289,4 +289,12 @@
 
         assertEquals(DOZE_PULSING, mMachine.getState());
     }
+
+    @Test
+    @UiThreadTest
+    public void testWakeUp_wakesUp() {
+        mMachine.wakeUp();
+
+        assertTrue(mServiceFake.requestedWakeup);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
index d12fc2c..c1e7fe4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
@@ -22,6 +22,7 @@
 
     public boolean finished;
     public int screenState;
+    public boolean requestedWakeup;
 
     public DozeServiceFake() {
         reset();
@@ -41,4 +42,9 @@
         finished = false;
         screenState = Display.STATE_UNKNOWN;
     }
+
+    @Override
+    public void requestWakeUp() {
+        requestedWakeup = true;
+    }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 245bf9e..36dee49 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3410,6 +3410,12 @@
     // OS: O
     NOTIFICATION_SNOOZED_CRITERIA = 832;
 
+    // FIELD - The context (source) from which an action is performed
+    FIELD_CONTEXT = 833;
+
+    // ACTION: Settings advanced button is expanded
+    ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index dc987fa..e6f6e57 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -901,7 +901,8 @@
             mPackagesToMonitorComponentChange.add(packageName);
         }
 
-        private boolean isChangingPackagesOfCurrentUser() {
+        @GuardedBy("mMethodMap")
+        private boolean isChangingPackagesOfCurrentUserLocked() {
             final int userId = getChangingUserId();
             final boolean retval = userId == mSettings.getCurrentUserId();
             if (DEBUG) {
@@ -914,10 +915,10 @@
 
         @Override
         public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
-            if (!isChangingPackagesOfCurrentUser()) {
-                return false;
-            }
             synchronized (mMethodMap) {
+                if (!isChangingPackagesOfCurrentUserLocked()) {
+                    return false;
+                }
                 String curInputMethodId = mSettings.getSelectedInputMethod();
                 final int N = mMethodList.size();
                 if (curInputMethodId != null) {
@@ -951,10 +952,10 @@
 
         @Override
         public void onSomePackagesChanged() {
-            if (!isChangingPackagesOfCurrentUser()) {
-                return;
-            }
             synchronized (mMethodMap) {
+                if (!isChangingPackagesOfCurrentUserLocked()) {
+                    return;
+                }
                 InputMethodInfo curIm = null;
                 String curInputMethodId = mSettings.getSelectedInputMethod();
                 final int N = mMethodList.size();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 42eb958..ef7780c 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.annotation.NonNull;
 import android.content.pm.PackageManagerInternal;
+import android.util.ArraySet;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
@@ -135,8 +136,6 @@
     private static final String FUSED_LOCATION_SERVICE_ACTION =
             "com.android.location.service.FusedLocationProvider";
 
-    private static final String GMSCORE_PACKAGE = "com.android.google.gms";
-
     private static final int MSG_LOCATION_CHANGED = 1;
 
     private static final long NANOS_PER_MILLI = 1000000L;
@@ -224,7 +223,7 @@
     private final ArrayList<LocationProviderProxy> mProxyProviders =
             new ArrayList<>();
 
-    private String[] mBackgroundThrottlePackageWhitelist = new String[]{};
+    private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
 
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -345,6 +344,8 @@
             mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
             updateUserProfiles(mCurrentUserId);
 
+            updateThrottlingWhitelistLocked();
+
             // prepare providers
             loadProvidersLocked();
             updateProvidersLocked();
@@ -380,14 +381,7 @@
                 @Override
                 public void onChange(boolean selfChange) {
                     synchronized (mLock) {
-                        String setting = Settings.Global.getString(
-                            mContext.getContentResolver(),
-                            Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
-                        if (setting == null) {
-                            setting = "";
-                        }
-
-                        mBackgroundThrottlePackageWhitelist = setting.split(",");
+                        updateThrottlingWhitelistLocked();
                         updateProvidersLocked();
                     }
                 }
@@ -1747,12 +1741,27 @@
         p.setRequest(providerRequest, worksource);
     }
 
+    private void updateThrottlingWhitelistLocked() {
+        String setting = Settings.Global.getString(
+            mContext.getContentResolver(),
+            Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+        if (setting == null) {
+            setting = "";
+        }
+
+        mBackgroundThrottlePackageWhitelist.clear();
+        mBackgroundThrottlePackageWhitelist.addAll(
+            SystemConfig.getInstance().getAllowUnthrottledLocation());
+        mBackgroundThrottlePackageWhitelist.addAll(
+            Arrays.asList(setting.split(",")));
+    }
+
     private boolean isThrottlingExemptLocked(Receiver receiver) {
         if (receiver.mUid == Process.SYSTEM_UID) {
             return true;
         }
 
-        if (receiver.mPackageName.equals(GMSCORE_PACKAGE)) {
+        if (mBackgroundThrottlePackageWhitelist.contains(receiver.mPackageName)) {
             return true;
         }
 
@@ -1762,12 +1771,6 @@
             }
         }
 
-        for (String whitelistedPackage : mBackgroundThrottlePackageWhitelist) {
-            if (receiver.mPackageName.equals(whitelistedPackage)) {
-                return true;
-            }
-        }
-
         return false;
     }
 
@@ -2999,6 +3002,13 @@
                 }
             }
 
+            if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
+                pw.println("  Throttling Whitelisted Packages:");
+                for (String packageName : mBackgroundThrottlePackageWhitelist) {
+                    pw.println("    " + packageName);
+                }
+            }
+
             pw.append("  fudger: ");
             mLocationFudger.dump(fd, pw,  args);
 
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 3e89852..b33538cb 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -603,7 +603,10 @@
             mScanResultKeys = new ArraySet<>(size);
             for (int i = 0; i < size; i++) {
                 ScanResult scanResult = scanResults.get(i);
-                mScanResultKeys.add(NetworkKey.createFromScanResult(scanResult));
+                NetworkKey key = NetworkKey.createFromScanResult(scanResult);
+                if (key != null) {
+                    mScanResultKeys.add(key);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index fbc4440..5c8024a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4087,9 +4087,10 @@
     }
 
     @Override
-    public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
+    public void addSharedAccountsFromParentUser(int parentUserId, int userId,
+            String opPackageName) {
         checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
-        Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
+        Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
         for (Account account : accounts) {
             addSharedAccountAsUser(account, userId);
         }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 7cb223d..1337046 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -448,7 +448,10 @@
                 mVerb = VERB_STARTING;
                 scheduleOpTimeOut();
                 service.startJob(mParams);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
+                // We catch 'Exception' because client-app malice or bugs might induce a wide
+                // range of possible exception-throw outcomes from startJob() and its handling
+                // of the client's ParcelableBundle extras.
                 Slog.e(TAG, "Error sending onStart message to '" +
                         mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
             }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index db712ae..b589057 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -66,6 +66,9 @@
     public static final int DEX_OPT_PERFORMED = 1;
     public static final int DEX_OPT_FAILED = -1;
 
+    /** Special library name that skips shared libraries check during compilation. */
+    public static final String SKIP_SHARED_LIBRARY_CHECK = "&";
+
     private final Installer mInstaller;
     private final Object mInstallLock;
 
@@ -274,7 +277,7 @@
                 // TODO(calin): maybe add a separate call.
                 mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
                         /*oatDir*/ null, dexoptFlags,
-                        compilerFilter, info.volumeUuid, /*sharedLibrariesPath*/ null);
+                        compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK);
             }
 
             return DEX_OPT_PERFORMED;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0d63f72..f43e468 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -545,9 +545,6 @@
 
     public static final int REASON_LAST = REASON_CORE_APP;
 
-    /** Special library name that skips shared libraries check during compilation. */
-    private static final String SKIP_SHARED_LIBRARY_CHECK = "&";
-
     /** All dangerous permission names in the same order as the events in MetricsEvent */
     private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
             Manifest.permission.READ_CALENDAR,
@@ -2401,7 +2398,7 @@
                                             DEXOPT_PUBLIC,
                                             getCompilerFilterForReason(REASON_SHARED_APK),
                                             StorageManager.UUID_PRIVATE_INTERNAL,
-                                            SKIP_SHARED_LIBRARY_CHECK);
+                                            PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK);
                                 }
                             } catch (FileNotFoundException e) {
                                 Slog.w(TAG, "Library not found: " + libPath);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 3085c9c..570259b 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1581,6 +1581,11 @@
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
                         + " still has an icon");
             }
+            if (si.hasMaskableBitmap() && !si.hasIconFile()) {
+                failed = true;
+                Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+                    + " has maskable bitmap but was not saved to a file.");
+            }
             if (si.hasIconFile() && si.hasIconResource()) {
                 failed = true;
                 Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index d8857b7..057e781 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1216,7 +1216,8 @@
         // he XML we'd lose the icon.  We just remove all dangling files after saving the XML.
         shortcut.setIconResourceId(0);
         shortcut.setIconResName(null);
-        shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES);
+        shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE |
+            ShortcutInfo.FLAG_MASKABLE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES);
     }
 
     public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
@@ -1351,7 +1352,8 @@
                         shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES);
                         return;
                     }
-                    case Icon.TYPE_BITMAP: {
+                    case Icon.TYPE_BITMAP:
+                    case Icon.TYPE_BITMAP_MASKABLE: {
                         bitmap = icon.getBitmap(); // Don't recycle in this case.
                         break;
                     }
@@ -1382,6 +1384,9 @@
 
                         shortcut.setBitmapPath(out.getFile().getAbsolutePath());
                         shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE);
+                        if (icon.getType() == Icon.TYPE_BITMAP_MASKABLE) {
+                            shortcut.addFlags(ShortcutInfo.FLAG_MASKABLE_BITMAP);
+                        }
                     } finally {
                         IoUtils.closeQuietly(out);
                     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2b2bb48..dd44aa0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -244,6 +244,8 @@
 
     private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";
 
+    private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
+
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
     private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -506,6 +508,8 @@
         boolean mAdminBroadcastPending = false;
         PersistableBundle mInitBundle = null;
 
+        long mPasswordTokenHandle = 0;
+
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
@@ -2557,6 +2561,13 @@
                 out.endTag(null, TAG_INITIALIZATION_BUNDLE);
             }
 
+            if (policy.mPasswordTokenHandle != 0) {
+                out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE);
+                out.attribute(null, ATTR_VALUE,
+                        Long.toString(policy.mPasswordTokenHandle));
+                out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE);
+            }
+
             out.endTag(null, "policies");
 
             out.endDocument();
@@ -2763,6 +2774,9 @@
                         m.symbols = Integer.parseInt(parser.getAttributeValue(null, "symbols"));
                         m.nonLetter = Integer.parseInt(parser.getAttributeValue(null, "nonletter"));
                     }
+                } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) {
+                    policy.mPasswordTokenHandle = Long.parseLong(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -4074,12 +4088,8 @@
             mInjector.binderRestoreCallingIdentity(token);
         }
     }
-
     @Override
     public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException {
-        if (!mHasFeature) {
-            return false;
-        }
         final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
@@ -4090,15 +4100,18 @@
             enforceNotManagedProfile(userHandle, "clear the active password");
         }
 
-        int quality;
         synchronized (this) {
             // If caller has PO (or DO) it can change the password, so see if that's the case first.
             ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
                     null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid);
             final boolean preN;
             if (admin != null) {
-                preN = getTargetSdk(admin.info.getPackageName(),
-                        userHandle) <= android.os.Build.VERSION_CODES.M;
+                final int targetSdk = getTargetSdk(admin.info.getPackageName(), userHandle);
+                if (targetSdk >= Build.VERSION_CODES.O) {
+                    throw new SecurityException("resetPassword() is deprecated for DPC targeting O"
+                            + " or later");
+                }
+                preN = targetSdk <= android.os.Build.VERSION_CODES.M;
             } else {
                 // Otherwise, make sure the caller has any active admin with the right policy.
                 admin = getActiveAdminForCallerLocked(null,
@@ -4149,7 +4162,15 @@
                     return false;
                 }
             }
+        }
 
+        return resetPasswordInternal(password, 0, null, flags, callingUid, userHandle);
+    }
+
+    private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token,
+            int flags, int callingUid, int userHandle) {
+        int quality;
+        synchronized (this) {
             quality = getPasswordQuality(null, userHandle, /* parent */ false);
             if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
                 quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -4239,11 +4260,20 @@
         // Don't do this with the lock held, because it is going to call
         // back in to the service.
         final long ident = mInjector.binderClearCallingIdentity();
+        final boolean result;
         try {
-            if (!TextUtils.isEmpty(password)) {
-                mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
+            if (token == null) {
+                if (!TextUtils.isEmpty(password)) {
+                    mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
+                } else {
+                    mLockPatternUtils.clearLock(null, userHandle);
+                }
+                result = true;
             } else {
-                mLockPatternUtils.clearLock(null, userHandle);
+                result = mLockPatternUtils.setLockCredentialWithToken(password,
+                        TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
+                                : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+                        tokenHandle, token, userHandle);
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
@@ -4260,8 +4290,7 @@
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
-
-        return true;
+        return result;
     }
 
     private boolean isLockScreenSecureUnchecked(int userId) {
@@ -9092,13 +9121,16 @@
             }
             final String deviceOwnerPackageName = mOwners.getDeviceOwnerComponent()
                     .getPackageName();
-            final String[] pkgs = mInjector.getPackageManager().getPackagesForUid(callerUid);
-
-            for (String pkg : pkgs) {
-                if (deviceOwnerPackageName.equals(pkg)) {
-                    return true;
+                try {
+                    String[] pkgs = mInjector.getIPackageManager().getPackagesForUid(callerUid);
+                    for (String pkg : pkgs) {
+                        if (deviceOwnerPackageName.equals(pkg)) {
+                            return true;
+                        }
+                    }
+                } catch (RemoteException e) {
+                    return false;
                 }
-            }
         }
 
         return false;
@@ -10621,4 +10653,98 @@
         enforceDeviceOwnerOrManageUsers();
         return getUserData(UserHandle.USER_SYSTEM).mLastNetworkLogsRetrievalTime;
     }
+
+    @Override
+    public boolean setResetPasswordToken(ComponentName admin, byte[] token) {
+        if (!mHasFeature) {
+            return false;
+        }
+        if (token == null || token.length < 32) {
+            throw new IllegalArgumentException("token must be at least 32-byte long");
+        }
+        synchronized (this) {
+            final int userHandle = mInjector.userHandleGetCallingUserId();
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            DevicePolicyData policy = getUserData(userHandle);
+            long ident = mInjector.binderClearCallingIdentity();
+            try {
+                if (policy.mPasswordTokenHandle != 0) {
+                    mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, userHandle);
+                }
+
+                policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token, userHandle);
+                saveSettingsLocked(userHandle);
+                return policy.mPasswordTokenHandle != 0;
+            } finally {
+                mInjector.binderRestoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
+    public boolean clearResetPasswordToken(ComponentName admin) {
+        if (!mHasFeature) {
+            return false;
+        }
+        synchronized (this) {
+            final int userHandle = mInjector.userHandleGetCallingUserId();
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            DevicePolicyData policy = getUserData(userHandle);
+            if (policy.mPasswordTokenHandle != 0) {
+                long ident = mInjector.binderClearCallingIdentity();
+                try {
+                    boolean result = mLockPatternUtils.removeEscrowToken(
+                            policy.mPasswordTokenHandle, userHandle);
+                    policy.mPasswordTokenHandle = 0;
+                    saveSettingsLocked(userHandle);
+                    return result;
+                } finally {
+                    mInjector.binderRestoreCallingIdentity(ident);
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isResetPasswordTokenActive(ComponentName admin) {
+        synchronized (this) {
+            final int userHandle = mInjector.userHandleGetCallingUserId();
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            DevicePolicyData policy = getUserData(userHandle);
+            if (policy.mPasswordTokenHandle != 0) {
+                long ident = mInjector.binderClearCallingIdentity();
+                try {
+                    return mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle,
+                            userHandle);
+                } finally {
+                    mInjector.binderRestoreCallingIdentity(ident);
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean resetPasswordWithToken(ComponentName admin, String passwordOrNull, byte[] token,
+            int flags) {
+        Preconditions.checkNotNull(token);
+        synchronized (this) {
+            final int userHandle = mInjector.userHandleGetCallingUserId();
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            DevicePolicyData policy = getUserData(userHandle);
+            if (policy.mPasswordTokenHandle != 0) {
+                final String password = passwordOrNull != null ? passwordOrNull : "";
+                return resetPasswordInternal(password, policy.mPasswordTokenHandle, token,
+                        flags, mInjector.binderGetCallingUid(), userHandle);
+            } else {
+                Slog.w(LOG_TAG, "No saved token handle");
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 3a88e9c..c0b79be 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -117,6 +117,7 @@
     private static final String SSID = "ssid";
     private static final String SSID_2 = "ssid_2";
     private static final String SSID_3 = "ssid_3";
+    private static final String INVALID_BSSID = "invalid_bssid";
     private static final ComponentName RECOMMENDATION_SERVICE_COMP =
             new ComponentName("newPackageName", "newScoringServiceClass");
     private static final ScoredNetwork SCORED_NETWORK =
@@ -778,6 +779,54 @@
     }
 
     @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_nullSsid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn(null);
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_noneSsid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_emptySsid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn("");
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_invalidBssid() throws Exception {
+        when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID);
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
     public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception {
         NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
                 new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
@@ -813,6 +862,24 @@
     }
 
     @Test
+    public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception {
+        List<ScanResult> invalidScanResults = Lists.newArrayList(
+                new ScanResult(),
+                createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid),
+                createScanResult(WifiSsid.NONE, SCORED_NETWORK.networkKey.wifiKey.bssid),
+                createScanResult(SSID, null),
+                createScanResult(SSID, INVALID_BSSID)
+        );
+        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
+                new NetworkScoreService.ScanResultsScoreCacheFilter(() -> invalidScanResults);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
     public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception {
         NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
                 new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a186b59..23a1bb4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -56,6 +56,7 @@
 
 import com.android.internal.R;
 import com.android.internal.util.ParcelableString;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserRestrictionsUtils;
@@ -3735,6 +3736,41 @@
                 dpm.getPermissionGrantState(admin1, app2, permission));
     }
 
+    public void testResetPasswordWithToken() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        // test token validation
+        try {
+            dpm.setResetPasswordToken(admin1, new byte[31]);
+            fail("should not have accepted tokens too short");
+        } catch (IllegalArgumentException expected) {
+        }
+        // test adding a token
+        final byte[] token = new byte[32];
+        final long handle = 123456;
+        final String password = "password";
+        when(mContext.lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM)))
+            .thenReturn(handle);
+        assertTrue(dpm.setResetPasswordToken(admin1, token));
+
+        // test password activation
+        when(mContext.lockPatternUtils.isEscrowTokenActive(eq(handle), eq(UserHandle.USER_SYSTEM)))
+            .thenReturn(true);
+        assertTrue(dpm.isResetPasswordTokenActive(admin1));
+
+        // test reset password with token
+        when(mContext.lockPatternUtils.setLockCredentialWithToken(eq(password),
+                eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), eq(handle), eq(token),
+                eq(UserHandle.USER_SYSTEM)))
+                .thenReturn(true);
+        assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0));
+
+        // test removing a token
+        when(mContext.lockPatternUtils.removeEscrowToken(eq(handle), eq(UserHandle.USER_SYSTEM)))
+                .thenReturn(true);
+        assertTrue(dpm.clearResetPasswordToken(admin1));
+    }
+
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
         when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                 userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index ed6779c..43e2610 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -174,6 +174,8 @@
                 anyInt(),
                 eq(UserHandle.getUserId(packageUid)));
 
+        doReturn(new String[] {admin.getPackageName()}).when(mMockContext.ipackageManager)
+            .getPackagesForUid(eq(packageUid));
         // Set up getPackageInfo().
         markPackageAsInstalled(admin.getPackageName(), ai, UserHandle.getUserId(packageUid));
     }
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 980aa2d..0c53167 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -75,7 +75,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.graphics.drawable.MaskableIconDrawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -244,6 +246,8 @@
         final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
         final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
                 getTestContext().getResources(), R.drawable.icon2));
+        final Icon icon3 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+            getTestContext().getResources(), R.drawable.icon2));
 
         final ShortcutInfo si1 = makeShortcut(
                 "shortcut1",
@@ -261,12 +265,18 @@
                 icon2,
                 makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
                 /* weight */ 12);
-        final ShortcutInfo si3 = makeShortcut("shortcut3");
+        final ShortcutInfo si3 = makeShortcut(
+                "shortcut3",
+                "Title 3",
+                /* activity */ null,
+                icon3,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 13);
 
-        assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
         assertShortcutIds(assertAllNotKeyFieldsOnly(
                 mManager.getDynamicShortcuts()),
-                "shortcut1", "shortcut2");
+                "shortcut1", "shortcut2", "shortcut3");
         assertEquals(2, mManager.getRemainingCallCount());
 
         // TODO: Check fields
@@ -550,7 +560,7 @@
 
         final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
                 getTestContext().getResources(), R.drawable.black_32x32));
-        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+        final Icon bmp64x64_maskable = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
                 getTestContext().getResources(), R.drawable.black_64x64));
         final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
                 getTestContext().getResources(), R.drawable.black_512x512));
@@ -561,7 +571,7 @@
                 makeShortcutWithIcon("res32x32", res32x32),
                 makeShortcutWithIcon("res64x64", res64x64),
                 makeShortcutWithIcon("bmp32x32", bmp32x32),
-                makeShortcutWithIcon("bmp64x64", bmp64x64),
+                makeShortcutWithIcon("bmp64x64", bmp64x64_maskable),
                 makeShortcutWithIcon("bmp512x512", bmp512x512),
                 makeShortcut("none")
         )));
@@ -691,6 +701,15 @@
         bmp = pfdToBitmap(
                 mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0));
         assertBitmapSize(128, 128, bmp);
+
+        Drawable dr = mLauncherApps.getShortcutIconDrawable(
+            makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0);
+        assertTrue(dr instanceof MaskableIconDrawable);
+        float viewportPercentage = 1 / (1 + 2 * MaskableIconDrawable.getExtraInsetPercentage());
+        assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage),
+            dr.getIntrinsicWidth());
+        assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage),
+            dr.getIntrinsicHeight());
     }
 
     public void testCleanupDanglingBitmaps() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 562de414..28ec4fd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -932,6 +932,74 @@
         dumpUserFile(USER_10);
     }
 
+    public void testShortcutInfoSaveAndLoad_maskableBitmap() throws InterruptedException {
+        mRunningUsers.put(USER_10, true);
+
+        setCaller(CALLING_PACKAGE_1, USER_10);
+
+        final Icon bmp32x32 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource(
+            getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+            .setId("id")
+            .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+            .setIcon(bmp32x32)
+            .setTitle("title")
+            .setText("text")
+            .setDisabledMessage("dismes")
+            .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+            .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+            .setRank(123)
+            .setExtras(pb)
+            .build();
+        sorig.setTimestamp(mInjectedCurrentTimeMillis);
+
+        mManager.addDynamicShortcuts(list(sorig));
+
+        mInjectedCurrentTimeMillis += 1;
+        final long now = mInjectedCurrentTimeMillis;
+        mInjectedCurrentTimeMillis += 1;
+
+        dumpsysOnLogcat("before save");
+
+        // Save and load.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_10);
+
+        dumpUserFile(USER_10);
+        dumpsysOnLogcat("after load");
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
+
+        assertEquals(USER_10, si.getUserId());
+        assertEquals(HANDLE_USER_10, si.getUserHandle());
+        assertEquals(CALLING_PACKAGE_1, si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(0, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
+            | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_MASKABLE_BITMAP,
+            si.getFlags());
+        assertNotNull(si.getBitmapPath()); // Something should be set.
+        assertEquals(0, si.getIconResourceId());
+        assertTrue(si.getLastChangedTimestamp() < now);
+
+        dumpUserFile(USER_10);
+    }
+
     public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
         mRunningUsers.put(USER_10, true);
 
diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java
index 803a7f1..18cab7b 100644
--- a/tools/preload2/src/com/android/preload/DeviceUtils.java
+++ b/tools/preload2/src/com/android/preload/DeviceUtils.java
@@ -16,13 +16,18 @@
 
 package com.android.preload;
 
+import com.android.ddmlib.AdbCommandRejectedException;
 import com.android.ddmlib.AndroidDebugBridge;
 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
 import com.android.preload.classdataretrieval.hprof.Hprof;
 import com.android.ddmlib.DdmPreferences;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.SyncException;
+import com.android.ddmlib.TimeoutException;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.Date;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -32,6 +37,18 @@
  */
 public class DeviceUtils {
 
+  // Locations
+  private static final String PRELOADED_CLASSES_FILE = "/etc/preloaded-classes";
+  // Shell commands
+  private static final String CREATE_EMPTY_PRELOADED_CMD = "touch " + PRELOADED_CLASSES_FILE;
+  private static final String DELETE_CACHE_CMD = "rm /data/dalvik-cache/*/*boot.art";
+  private static final String DELETE_PRELOADED_CMD = "rm " + PRELOADED_CLASSES_FILE;
+  private static final String READ_PRELOADED_CMD = "cat " + PRELOADED_CLASSES_FILE;
+  private static final String START_SHELL_CMD = "start";
+  private static final String STOP_SHELL_CMD = "stop";
+  private static final String REMOUNT_SYSTEM_CMD = "mount -o rw,remount /system";
+  private static final String UNSET_BOOTCOMPLETE_CMD = "setprop dev.bootcomplete \"0\"";
+
   public static void init(int debugPort) {
     DdmPreferences.setSelectedDebugPort(debugPort);
 
@@ -119,43 +136,56 @@
     return !ret.contains("No such file or directory");
   }
 
-  /**
-   * Remove files involved in a standard build that interfere with collecting data. This will
-   * remove /etc/preloaded-classes, which determines which classes are allocated already in the
-   * boot image. It also deletes any compiled boot image on the device. Then it restarts the
-   * device.
-   *
-   * This is a potentially long-running operation, as the boot after the deletion may take a while.
-   * The method will abort after the given timeout.
-   */
-  public static boolean removePreloaded(IDevice device, long preloadedWaitTimeInSeconds) {
-    String oldContent =
-        DeviceUtils.doShellReturnString(device, "cat /etc/preloaded-classes", 1, TimeUnit.SECONDS);
-    if (oldContent.trim().equals("")) {
-      System.out.println("Preloaded-classes already empty.");
-      return true;
-    }
+    /**
+     * Write over the preloaded-classes file with an empty or existing file and regenerate the boot
+     * image as necessary.
+     *
+     * @param device
+     * @param pcFile
+     * @param bootTimeout
+     * @throws AdbCommandRejectedException
+     * @throws IOException
+     * @throws TimeoutException
+     * @throws SyncException
+     * @return true if successfully overwritten, false otherwise
+     */
+    public static boolean overwritePreloaded(IDevice device, File pcFile, long bootTimeout)
+            throws AdbCommandRejectedException, IOException, TimeoutException, SyncException {
+        boolean writeEmpty = (pcFile == null);
+        if (writeEmpty) {
+            // Check if the preloaded-classes file is already empty.
+            String oldContent =
+                    doShellReturnString(device, READ_PRELOADED_CMD, 1, TimeUnit.SECONDS);
+            if (oldContent.trim().equals("")) {
+                System.out.println("Preloaded-classes already empty.");
+                return true;
+            }
+        }
 
-    // Stop the system server etc.
-    doShell(device, "stop", 100, TimeUnit.MILLISECONDS);
+        // Stop the system server etc.
+        doShell(device, STOP_SHELL_CMD, 1, TimeUnit.SECONDS);
+        // Remount the read-only system partition
+        doShell(device, REMOUNT_SYSTEM_CMD, 1, TimeUnit.SECONDS);
+        // Delete the preloaded-classes file
+        doShell(device, DELETE_PRELOADED_CMD, 1, TimeUnit.SECONDS);
+        // Delete the dalvik cache files
+        doShell(device, DELETE_CACHE_CMD, 1, TimeUnit.SECONDS);
+        if (writeEmpty) {
+            // Write an empty preloaded-classes file
+            doShell(device, CREATE_EMPTY_PRELOADED_CMD, 500, TimeUnit.MILLISECONDS);
+        } else {
+            // Push the new preloaded-classes file
+            device.pushFile(pcFile.getAbsolutePath(), PRELOADED_CLASSES_FILE);
+        }
+        // Manually reset the boot complete flag
+        doShell(device, UNSET_BOOTCOMPLETE_CMD, 1, TimeUnit.SECONDS);
+        // Restart system server on the device
+        doShell(device, START_SHELL_CMD, 1, TimeUnit.SECONDS);
+        // Wait for the boot complete flag and return the outcome.
+        return waitForBootComplete(device, bootTimeout);
+  }
 
-    // Remount /system, delete /etc/preloaded-classes. It would be nice to use "adb remount,"
-    // but AndroidDebugBridge doesn't expose it.
-    doShell(device, "mount -o remount,rw /system", 500, TimeUnit.MILLISECONDS);
-    doShell(device, "rm /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS);
-    // We do need an empty file.
-    doShell(device, "touch /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS);
-
-    // Delete the files in the dalvik cache.
-    doShell(device, "rm /data/dalvik-cache/*/*boot.art", 500, TimeUnit.MILLISECONDS);
-
-    // We'll try to use dev.bootcomplete to know when the system server is back up. But stop
-    // doesn't reset it, so do it manually.
-    doShell(device, "setprop dev.bootcomplete \"0\"", 500, TimeUnit.MILLISECONDS);
-
-    // Start the system server.
-    doShell(device, "start", 100, TimeUnit.MILLISECONDS);
-
+  private static boolean waitForBootComplete(IDevice device, long timeout) {
     // Do a loop checking each second whether bootcomplete. Wait for at most the given
     // threshold.
     Date startDate = new Date();
@@ -178,7 +208,7 @@
       Date endDate = new Date();
       long seconds =
           TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS);
-      if (seconds > preloadedWaitTimeInSeconds) {
+      if (seconds > timeout) {
         return false;
       }
     }
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
index c42a19b..2265e95 100644
--- a/tools/preload2/src/com/android/preload/Main.java
+++ b/tools/preload2/src/com/android/preload/Main.java
@@ -29,6 +29,7 @@
 import com.android.preload.actions.ScanAllPackagesAction;
 import com.android.preload.actions.ScanPackageAction;
 import com.android.preload.actions.ShowDataAction;
+import com.android.preload.actions.WritePreloadedClassesAction;
 import com.android.preload.classdataretrieval.ClassDataRetriever;
 import com.android.preload.classdataretrieval.hprof.Hprof;
 import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
@@ -96,6 +97,7 @@
     public final static String COMPUTE_FILE_CMD = "comp";
     public final static String EXPORT_CMD = "export";
     public final static String IMPORT_CMD = "import";
+    public final static String WRITE_CMD = "write";
 
     /**
      * @param args
@@ -132,6 +134,7 @@
                 null));
         actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
                 CLASS_PRELOAD_BLACKLIST));
+        actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel));
         actions.add(new ShowDataAction(dataTableModel));
         actions.add(new ImportAction(dataTableModel));
         actions.add(new ExportAction(dataTableModel));
@@ -200,6 +203,11 @@
                     ui.input(it.next());
                     ui.confirmYes();
                     ui.output(new File(it.next()));
+                // Operation: Write preloaded classes from a specific file
+                } else if (WRITE_CMD.equals(op)) {
+                    System.out.println("Writing preloaded classes.");
+                    ui.action(WritePreloadedClassesAction.class);
+                    ui.input(new File(it.next()));
                 }
             }
         } catch (NoSuchElementException e) {
@@ -305,8 +313,16 @@
 
             Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
                     + "long time. Please be patient.");
-            if (!DeviceUtils.removePreloaded(device, 15 * 60) /* 15m timeout */) {
-                Main.getUI().showMessageDialog("Removing preloaded-classes failed unexpectedly!");
+            boolean success = false;
+            try {
+                success = DeviceUtils.overwritePreloaded(device, null, 15 * 60);
+            } catch (Exception e) {
+                System.err.println(e);
+            } finally {
+                if (!success) {
+                    Main.getUI().showMessageDialog(
+                            "Removing preloaded-classes failed unexpectedly!");
+                }
             }
         }
     }
diff --git a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
new file mode 100644
index 0000000..9b97f11
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.preload.ClientUtils;
+import com.android.preload.DeviceUtils;
+import com.android.preload.DumpData;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.Date;
+import java.util.Map;
+
+public class WritePreloadedClassesAction extends AbstractThreadedDeviceSpecificAction {
+    private File preloadedClassFile;
+
+    public WritePreloadedClassesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
+        super("Write preloaded classes action", device);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        File[] files = Main.getUI().showOpenDialog(true);
+        if (files != null && files.length > 0) {
+            preloadedClassFile = files[0];
+            super.actionPerformed(e);
+        }
+    }
+
+    @Override
+    public void run() {
+        Main.getUI().showWaitDialog();
+        try {
+            // Write the new file with a 5-minute timeout
+            DeviceUtils.overwritePreloaded(device, preloadedClassFile, 5 * 60);
+        } catch (Exception e) {
+            System.err.println(e);
+        } finally {
+            Main.getUI().hideWaitDialog();
+        }
+    }
+}