Merge "Revert "Window Manager Flag Migration (4/n)""
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 3cfb080..c036c77 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -35,8 +35,6 @@
 
     void onBootPhase(int phase);
 
-    boolean isParoledOrCharging();
-
     void postCheckIdleStates(int userId);
 
     /**
@@ -59,13 +57,15 @@
 
     int getAppId(String packageName);
 
-    boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
+    /**
+     * @see #isAppIdleFiltered(String, int, int, long)
+     */
+    boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime,
             boolean shouldObfuscateInstantApps);
 
     /**
      * Checks if an app has been idle for a while and filters out apps that are excluded.
      * It returns false if the current system state allows all apps to be considered active.
-     * This happens if the device is plugged in or temporarily allowed to make exceptions.
      * Called by interface impls.
      */
     boolean isAppIdleFiltered(String packageName, int appId, int userId,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 14d5a68..c3ffad6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -266,11 +266,6 @@
     boolean mReportedActive;
 
     /**
-     * Are we currently in device-wide standby parole?
-     */
-    volatile boolean mInParole;
-
-    /**
      * A mapping of which uids are currently in the foreground to their effective priority.
      */
     final SparseIntArray mUidPriorityOverride = new SparseIntArray();
@@ -2361,14 +2356,6 @@
         }
 
         @Override
-        public void onParoleStateChanged(boolean isParoleOn) {
-            if (DEBUG_STANDBY) {
-                Slog.i(TAG, "Global parole state now " + (isParoleOn ? "ON" : "OFF"));
-            }
-            mInParole = isParoleOn;
-        }
-
-        @Override
         public void onUserInteractionStarted(String packageName, int userId) {
             final int uid = mLocalPM.getPackageUid(packageName,
                     PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
@@ -3031,10 +3018,6 @@
             }
             pw.println();
 
-            pw.print("    In parole?: ");
-            pw.print(mInParole);
-            pw.println();
-
             for (int i = mJobRestrictions.size() - 1; i >= 0; i--) {
                 pw.print("    ");
                 mJobRestrictions.get(i).dumpConstants(pw);
@@ -3222,7 +3205,6 @@
             }
             proto.end(settingsToken);
 
-            proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole);
             for (int i = mJobRestrictions.size() - 1; i >= 0; i--) {
                 mJobRestrictions.get(i).dumpConstants(proto);
             }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 400d902..14dce84 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -414,8 +414,6 @@
     private final Handler mHandler;
     private final QcConstants mQcConstants;
 
-    private volatile boolean mInParole;
-
     /** How much time each app will have to run jobs within their standby bucket window. */
     private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
 
@@ -711,7 +709,6 @@
     public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) {
         // If quota is currently "free", then the job can run for the full amount of time.
         if (mChargeTracker.isCharging()
-                || mInParole
                 || isTopStartedJobLocked(jobStatus)
                 || isUidInForeground(jobStatus.getSourceUid())) {
             return JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
@@ -737,8 +734,8 @@
             final int standbyBucket) {
         if (standbyBucket == NEVER_INDEX) return false;
 
-        // Quota constraint is not enforced while charging or when parole is on.
-        if (mChargeTracker.isCharging() || mInParole) {
+        // Quota constraint is not enforced while charging.
+        if (mChargeTracker.isCharging()) {
             return true;
         }
 
@@ -1780,20 +1777,6 @@
                 }
             });
         }
-
-        @Override
-        public void onParoleStateChanged(final boolean isParoleOn) {
-            mInParole = isParoleOn;
-            if (DEBUG) {
-                Slog.i(TAG, "Global parole state now " + (isParoleOn ? "ON" : "OFF"));
-            }
-            // Update job bookkeeping out of band.
-            BackgroundThread.getHandler().post(() -> {
-                synchronized (mLock) {
-                    maybeUpdateAllConstraintsLocked();
-                }
-            });
-        }
     }
 
     private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> {
@@ -2515,7 +2498,6 @@
     public void dumpControllerStateLocked(final IndentingPrintWriter pw,
             final Predicate<JobStatus> predicate) {
         pw.println("Is charging: " + mChargeTracker.isCharging());
-        pw.println("In parole: " + mInParole);
         pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
         pw.println();
 
@@ -2639,7 +2621,6 @@
         final long mToken = proto.start(StateControllerProto.QUOTA);
 
         proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
-        proto.write(StateControllerProto.QuotaController.IS_IN_PAROLE, mInParole);
         proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME,
                 sElapsedRealtimeClock.millis());
 
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 7c472a9..ecc0459 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -45,7 +45,6 @@
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
 
-import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
 
 import android.annotation.UserIdInt;
@@ -70,10 +69,8 @@
 import android.hardware.display.DisplayManager;
 import android.net.ConnectivityManager;
 import android.net.Network;
-import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkScoreManager;
-import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Environment;
 import android.os.Handler;
@@ -192,21 +189,14 @@
     static final int MSG_INFORM_LISTENERS = 3;
     static final int MSG_FORCE_IDLE_STATE = 4;
     static final int MSG_CHECK_IDLE_STATES = 5;
-    static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
-    static final int MSG_PAROLE_END_TIMEOUT = 7;
     static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
-    static final int MSG_PAROLE_STATE_CHANGED = 9;
     static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
     /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
     static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
     static final int MSG_REPORT_SYNC_SCHEDULED = 12;
     static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
-    static final int MSG_UPDATE_STABLE_CHARGING= 14;
 
     long mCheckIdleIntervalMillis;
-    long mAppIdleParoleIntervalMillis;
-    long mAppIdleParoleWindowMillis;
-    long mAppIdleParoleDurationMillis;
     long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
     long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
     /** Minimum time a strong usage event should keep the bucket elevated. */
@@ -244,20 +234,12 @@
      * start is the first usage of the app
      */
     long mInitialForegroundServiceStartTimeoutMillis;
-    /** The length of time phone must be charging before considered stable enough to run jobs  */
-    long mStableChargingThresholdMillis;
 
     private volatile boolean mAppIdleEnabled;
-    boolean mAppIdleTempParoled;
-    boolean mCharging;
-    boolean mChargingStable;
-    private long mLastAppIdleParoledTime;
     private boolean mSystemServicesReady = false;
     // There was a system update, defaults need to be initialized after services are ready
     private boolean mPendingInitializeDefaults;
 
-    private final DeviceStateReceiver mDeviceStateReceiver;
-
     private volatile boolean mPendingOneTimeCheckIdleStates;
 
     private final AppStandbyHandler mHandler;
@@ -267,7 +249,6 @@
 
     private AppWidgetManager mAppWidgetManager;
     private ConnectivityManager mConnectivityManager;
-    private PowerManager mPowerManager;
     private PackageManager mPackageManager;
     Injector mInjector;
 
@@ -329,12 +310,6 @@
         mContext = mInjector.getContext();
         mHandler = new AppStandbyHandler(mInjector.getLooper());
         mPackageManager = mContext.getPackageManager();
-        mDeviceStateReceiver = new DeviceStateReceiver();
-
-        IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
-        deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
-        deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-        mContext.registerReceiver(mDeviceStateReceiver, deviceStates);
 
         synchronized (mAppIdleLock) {
             mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
@@ -353,15 +328,7 @@
 
     @VisibleForTesting
     void setAppIdleEnabled(boolean enabled) {
-        synchronized (mAppIdleLock) {
-            if (mAppIdleEnabled != enabled) {
-                final boolean oldParoleState = isParoledOrCharging();
-                mAppIdleEnabled = enabled;
-                if (isParoledOrCharging() != oldParoleState) {
-                    postParoleStateChanged();
-                }
-            }
-        }
+        mAppIdleEnabled = enabled;
     }
 
     @Override
@@ -381,7 +348,6 @@
 
             mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
             mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
-            mPowerManager = mContext.getSystemService(PowerManager.class);
 
             mInjector.registerDisplayListener(mDisplayListener, mHandler);
             synchronized (mAppIdleLock) {
@@ -402,8 +368,6 @@
             if (mPendingOneTimeCheckIdleStates) {
                 postOneTimeCheckIdleStates();
             }
-        } else if (phase == PHASE_BOOT_COMPLETED) {
-            setChargingState(mInjector.isCharging());
         }
     }
 
@@ -504,93 +468,6 @@
         }
     }
 
-    @VisibleForTesting
-    void setChargingState(boolean charging) {
-        synchronized (mAppIdleLock) {
-            if (mCharging != charging) {
-                mCharging = charging;
-                if (DEBUG) Slog.d(TAG, "Setting mCharging to " + charging);
-                if (charging) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Scheduling MSG_UPDATE_STABLE_CHARGING  delay = "
-                                + mStableChargingThresholdMillis);
-                    }
-                    mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STABLE_CHARGING,
-                            mStableChargingThresholdMillis);
-                } else {
-                    mHandler.removeMessages(MSG_UPDATE_STABLE_CHARGING);
-                    updateChargingStableState();
-                }
-            }
-        }
-    }
-
-    private void updateChargingStableState() {
-        synchronized (mAppIdleLock) {
-            if (mChargingStable != mCharging) {
-                if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging);
-                mChargingStable = mCharging;
-                postParoleStateChanged();
-            }
-        }
-    }
-
-    private void setAppIdleParoled(boolean paroled) {
-        synchronized (mAppIdleLock) {
-            final long now = mInjector.currentTimeMillis();
-            if (mAppIdleTempParoled != paroled) {
-                mAppIdleTempParoled = paroled;
-                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
-                if (paroled) {
-                    postParoleEndTimeout();
-                } else {
-                    mLastAppIdleParoledTime = now;
-                    postNextParoleTimeout(now, false);
-                }
-                postParoleStateChanged();
-            }
-        }
-    }
-
-    @Override
-    public boolean isParoledOrCharging() {
-        if (!mAppIdleEnabled) return true;
-        synchronized (mAppIdleLock) {
-            // Only consider stable charging when determining charge state.
-            return mAppIdleTempParoled || mChargingStable;
-        }
-    }
-
-    private void postNextParoleTimeout(long now, boolean forced) {
-        if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
-        mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
-        // Compute when the next parole needs to happen. We check more frequently than necessary
-        // since the message handler delays are based on elapsedRealTime and not wallclock time.
-        // The comparison is done in wallclock time.
-        long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
-        if (forced) {
-            // Set next timeout for the end of the parole window
-            // If parole is not set by the end of the window it will be forced
-            timeLeft += mAppIdleParoleWindowMillis;
-        }
-        if (timeLeft < 0) {
-            timeLeft = 0;
-        }
-        mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft);
-    }
-
-    private void postParoleEndTimeout() {
-        if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_END_TIMEOUT");
-        mHandler.removeMessages(MSG_PAROLE_END_TIMEOUT);
-        mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
-    }
-
-    private void postParoleStateChanged() {
-        if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
-        mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
-        mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
-    }
-
     @Override
     public void postCheckIdleStates(int userId) {
         mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
@@ -787,48 +664,6 @@
         return THRESHOLD_BUCKETS[bucketIndex];
     }
 
-    private void checkParoleTimeout() {
-        boolean setParoled = false;
-        boolean waitForNetwork = false;
-        NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
-        boolean networkActive = activeNetwork != null &&
-                activeNetwork.isConnected();
-
-        synchronized (mAppIdleLock) {
-            final long now = mInjector.currentTimeMillis();
-            if (!mAppIdleTempParoled) {
-                final long timeSinceLastParole = now - mLastAppIdleParoledTime;
-                if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
-                    if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
-                    if (networkActive) {
-                        // If network is active set parole
-                        setParoled = true;
-                    } else {
-                        if (timeSinceLastParole
-                                > mAppIdleParoleIntervalMillis + mAppIdleParoleWindowMillis) {
-                            if (DEBUG) Slog.d(TAG, "Crossed end of parole window, force parole");
-                            setParoled = true;
-                        } else {
-                            if (DEBUG) Slog.d(TAG, "Network unavailable, delaying parole");
-                            waitForNetwork = true;
-                            postNextParoleTimeout(now, true);
-                        }
-                    }
-                } else {
-                    if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
-                    postNextParoleTimeout(now, false);
-                }
-            }
-        }
-        if (waitForNetwork) {
-            mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
-        }
-        if (setParoled) {
-            // Set parole if network is available
-            setAppIdleParoled(true);
-        }
-    }
-
     private void notifyBatteryStats(String packageName, int userId, boolean idle) {
         try {
             final int uid = mPackageManager.getPackageUidAsUser(packageName,
@@ -844,30 +679,6 @@
         }
     }
 
-    private void onDeviceIdleModeChanged() {
-        final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
-        if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
-        boolean paroled = false;
-        synchronized (mAppIdleLock) {
-            final long timeSinceLastParole =
-                    mInjector.currentTimeMillis() - mLastAppIdleParoledTime;
-            if (!deviceIdle
-                    && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
-                if (DEBUG) {
-                    Slog.i(TAG,
-                            "Bringing idle apps out of inactive state due to deviceIdleMode=false");
-                }
-                paroled = true;
-            } else if (deviceIdle) {
-                if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
-                paroled = false;
-            } else {
-                return;
-            }
-        }
-        setAppIdleParoled(paroled);
-    }
-
     @Override
     public void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
         if (!mAppIdleEnabled) return;
@@ -1038,11 +849,8 @@
     }
 
     @Override
-    public boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
+    public boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime,
             boolean shouldObfuscateInstantApps) {
-        if (isParoledOrCharging()) {
-            return false;
-        }
         if (shouldObfuscateInstantApps &&
                 mInjector.isPackageEphemeral(userId, packageName)) {
             return false;
@@ -1388,15 +1196,6 @@
         }
     }
 
-    private void informParoleStateChanged() {
-        final boolean paroled = isParoledOrCharging();
-        synchronized (mPackageAccessListeners) {
-            for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
-                listener.onParoleStateChanged(paroled);
-            }
-        }
-    }
-
     @Override
     public void flushToDisk(int userId) {
         synchronized (mAppIdleLock) {
@@ -1517,18 +1316,6 @@
         TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
         pw.println();
 
-        pw.print("  mAppIdleParoleIntervalMillis=");
-        TimeUtils.formatDuration(mAppIdleParoleIntervalMillis, pw);
-        pw.println();
-
-        pw.print("  mAppIdleParoleWindowMillis=");
-        TimeUtils.formatDuration(mAppIdleParoleWindowMillis, pw);
-        pw.println();
-
-        pw.print("  mAppIdleParoleDurationMillis=");
-        TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
-        pw.println();
-
         pw.print("  mStrongUsageTimeoutMillis=");
         TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw);
         pw.println();
@@ -1566,22 +1353,11 @@
         TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw);
         pw.println();
 
-        pw.print("  mStableChargingThresholdMillis=");
-        TimeUtils.formatDuration(mStableChargingThresholdMillis, pw);
-        pw.println();
-
         pw.println();
         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
-        pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
-        pw.print(" mCharging="); pw.print(mCharging);
-        pw.print(" mChargingStable="); pw.print(mChargingStable);
-        pw.print(" mLastAppIdleParoledTime=");
-        TimeUtils.formatDuration(now - mLastAppIdleParoledTime, pw);
         pw.println();
         pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
         pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
-        pw.print("mStableChargingThresholdMillis=");
-        TimeUtils.formatDuration(mStableChargingThresholdMillis, pw);
         pw.println();
     }
 
@@ -1655,10 +1431,6 @@
             return buildFlag && runtimeFlag;
         }
 
-        boolean isCharging() {
-            return mContext.getSystemService(BatteryManager.class).isCharging();
-        }
-
         boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
             return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
         }
@@ -1748,15 +1520,6 @@
                     checkIdleStates(UserHandle.USER_ALL);
                     break;
 
-                case MSG_CHECK_PAROLE_TIMEOUT:
-                    checkParoleTimeout();
-                    break;
-
-                case MSG_PAROLE_END_TIMEOUT:
-                    if (DEBUG) Slog.d(TAG, "Ending parole");
-                    setAppIdleParoled(false);
-                    break;
-
                 case MSG_REPORT_CONTENT_PROVIDER_USAGE:
                     SomeArgs args = (SomeArgs) msg.obj;
                     reportContentProviderUsage((String) args.arg1, // authority name
@@ -1765,11 +1528,6 @@
                     args.recycle();
                     break;
 
-                case MSG_PAROLE_STATE_CHANGED:
-                    if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
-                            + ", Charging state:" + mChargingStable);
-                    informParoleStateChanged();
-                    break;
                 case MSG_CHECK_PACKAGE_IDLE_STATE:
                     checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
                             mInjector.elapsedRealtime());
@@ -1788,10 +1546,6 @@
                     reportExemptedSyncStart((String) msg.obj, msg.arg1);
                     break;
 
-                case MSG_UPDATE_STABLE_CHARGING:
-                    updateChargingStableState();
-                    break;
-
                 default:
                     super.handleMessage(msg);
                     break;
@@ -1800,23 +1554,6 @@
         }
     };
 
-    private class DeviceStateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            switch (intent.getAction()) {
-                case BatteryManager.ACTION_CHARGING:
-                    setChargingState(true);
-                    break;
-                case BatteryManager.ACTION_DISCHARGING:
-                    setChargingState(false);
-                    break;
-                case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
-                    onDeviceIdleModeChanged();
-                    break;
-            }
-        }
-    }
-
     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build();
 
     private final ConnectivityManager.NetworkCallback mNetworkCallback
@@ -1824,7 +1561,6 @@
         @Override
         public void onAvailable(Network network) {
             mConnectivityManager.unregisterNetworkCallback(this);
-            checkParoleTimeout();
         }
     };
 
@@ -1851,9 +1587,6 @@
      * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
      */
     private class SettingsObserver extends ContentObserver {
-        private static final String KEY_PAROLE_INTERVAL = "parole_interval";
-        private static final String KEY_PAROLE_WINDOW = "parole_window";
-        private static final String KEY_PAROLE_DURATION = "parole_duration";
         private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
         private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
         private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
@@ -1875,7 +1608,6 @@
                 "system_interaction_duration";
         private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION =
                 "initial_foreground_service_start_duration";
-        private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
         public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
         public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
@@ -1885,7 +1617,6 @@
         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
         public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
-        public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
         public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1932,17 +1663,6 @@
 
             synchronized (mAppIdleLock) {
 
-                // Default: 24 hours between paroles
-                mAppIdleParoleIntervalMillis = mParser.getDurationMillis(KEY_PAROLE_INTERVAL,
-                        COMPRESS_TIME ? ONE_MINUTE * 10 : 24 * 60 * ONE_MINUTE);
-
-                // Default: 2 hours to wait on network
-                mAppIdleParoleWindowMillis = mParser.getDurationMillis(KEY_PAROLE_WINDOW,
-                        COMPRESS_TIME ? ONE_MINUTE * 2 : 2 * 60 * ONE_MINUTE);
-
-                mAppIdleParoleDurationMillis = mParser.getDurationMillis(KEY_PAROLE_DURATION,
-                        COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE); // 10 minutes
-
                 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null);
                 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
                         SCREEN_TIME_THRESHOLDS);
@@ -1997,10 +1717,6 @@
                         KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION,
                         COMPRESS_TIME ? ONE_MINUTE :
                                 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT);
-
-                mStableChargingThresholdMillis = mParser.getDurationMillis(
-                        KEY_STABLE_CHARGING_THRESHOLD,
-                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
             }
 
             // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
diff --git a/api/current.txt b/api/current.txt
index 40106b3..019ae84 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2946,6 +2946,7 @@
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
     field public static final int FEEDBACK_VISUAL = 8; // 0x8
     field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80
+    field public static final int FLAG_HANDLE_SHORTCUT = 2048; // 0x800
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
     field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
@@ -4481,7 +4482,7 @@
     method @IntRange(from=0) public int getNotingUid();
     method @NonNull public String getOp();
     method @IntRange(from=0) public long getTime();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AsyncNotedAppOp> CREATOR;
   }
 
@@ -25419,22 +25420,22 @@
   public class MediaMetadataRetriever implements java.lang.AutoCloseable {
     ctor public MediaMetadataRetriever();
     method public void close();
-    method public String extractMetadata(int);
-    method public byte[] getEmbeddedPicture();
-    method public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
-    method public android.graphics.Bitmap getFrameAtIndex(int);
-    method public android.graphics.Bitmap getFrameAtTime(long, int);
-    method public android.graphics.Bitmap getFrameAtTime(long, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
-    method public android.graphics.Bitmap getFrameAtTime(long);
-    method public android.graphics.Bitmap getFrameAtTime();
+    method @Nullable public String extractMetadata(int);
+    method @Nullable public byte[] getEmbeddedPicture();
+    method @Nullable public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+    method @Nullable public android.graphics.Bitmap getFrameAtIndex(int);
+    method @Nullable public android.graphics.Bitmap getFrameAtTime(long, int);
+    method @Nullable public android.graphics.Bitmap getFrameAtTime(long, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+    method @Nullable public android.graphics.Bitmap getFrameAtTime(long);
+    method @Nullable public android.graphics.Bitmap getFrameAtTime();
     method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
     method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int);
-    method public android.graphics.Bitmap getImageAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
-    method public android.graphics.Bitmap getImageAtIndex(int);
-    method public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
-    method public android.graphics.Bitmap getPrimaryImage();
-    method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
-    method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+    method @Nullable public android.graphics.Bitmap getImageAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+    method @Nullable public android.graphics.Bitmap getImageAtIndex(int);
+    method @Nullable public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
+    method @Nullable public android.graphics.Bitmap getPrimaryImage();
+    method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
+    method @Nullable public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
     method public void release();
     method public void setDataSource(String) throws java.lang.IllegalArgumentException;
     method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
@@ -40856,7 +40857,7 @@
     field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
     field public static final String EXTRA_NAME = "name";
     field public static final String EXTRA_PKCS12 = "PKCS12";
-    field public static final String KEY_ALIAS_SELECTION_DENIED = "alias-selection-denied-ef829e15-210a-409d-96c9-ee684fc41972";
+    field public static final String KEY_ALIAS_SELECTION_DENIED = "android:alias-selection-denied";
   }
 
   public interface KeyChainAliasCallback {
@@ -41917,6 +41918,7 @@
     field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
     field public static final String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
     field public static final String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
+    field public static final String META_DATA_BOOLEAN_TILE = "android.service.quicksettings.BOOLEAN_TILE";
   }
 
 }
@@ -44255,6 +44257,7 @@
     field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
     field public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
     field public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
+    field public static final String KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING = "default_vm_number_roaming_and_ims_unregistered_string";
     field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
     field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
diff --git a/api/system-current.txt b/api/system-current.txt
index 46413d3..6e35200 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -172,6 +172,7 @@
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
+    field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS";
     field public static final String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES";
@@ -5701,7 +5702,10 @@
 package android.permission {
 
   public final class PermissionControllerManager {
+    method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
     method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
     field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
     field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2
     field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
@@ -5715,17 +5719,19 @@
 
   public abstract class PermissionControllerService extends android.app.Service {
     ctor public PermissionControllerService();
+    method @BinderThread public void onApplyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @NonNull public final android.os.IBinder onBind(android.content.Intent);
     method @BinderThread public abstract void onCountPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull java.util.function.IntConsumer);
     method @BinderThread public abstract void onGetAppPermissions(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionPresentationInfo>>);
     method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
     method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);
     method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable);
-    method @BinderThread public abstract void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @BinderThread public abstract void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
+    method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
     method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
     method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
     method @BinderThread public void onUpdateUserSensitive();
     field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 9b85b96..b9ab375 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2253,8 +2253,11 @@
 package android.permission {
 
   public final class PermissionControllerManager {
+    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler);
+    method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
     method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
     field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
     field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2
     field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
@@ -2795,6 +2798,10 @@
     method public void exitBackgroundAudioProcessing(boolean);
   }
 
+  public static class Call.Details {
+    method public String getTelecomCallId();
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>);
   }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4603f08..47fdcde 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -850,6 +850,7 @@
         GestureResultCallbackInfo callbackInfo;
         synchronized (mLock) {
             callbackInfo = mGestureStatusCallbackInfos.get(sequence);
+            mGestureStatusCallbackInfos.remove(sequence);
         }
         final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
         if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index cf24b8e..e738b19 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
 
+import android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
@@ -322,6 +323,14 @@
      */
     public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400;
 
+    /**
+     * This flag indicates that the accessibility service will handle the shortcut action itself.
+     * A callback {@link AccessibilityButtonCallback#onClicked(AccessibilityButtonController)} is
+     * called when the user presses the accessibility shortcut. Otherwise, the service is enabled
+     * or disabled by the system instead.
+     */
+    public static final int FLAG_HANDLE_SHORTCUT = 0x00000800;
+
     /** {@hide} */
     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
 
@@ -423,12 +432,13 @@
      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
      * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
+     * @see #FLAG_HANDLE_SHORTCUT
      */
     public int flags;
 
     /**
      * Whether or not the service has crashed and is awaiting restart. Only valid from {@link
-     * android.view.accessibility.AccessibilityManager#getEnabledAccessibilityServiceList(int)},
+     * android.view.accessibility.AccessibilityManager#getInstalledAccessibilityServiceList()},
      * because that is populated from the internal list of running services.
      *
      * @hide
@@ -1103,6 +1113,8 @@
                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
             case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
                 return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
+            case FLAG_HANDLE_SHORTCUT:
+                return "FLAG_HANDLE_SHORTCUT";
             default:
                 return null;
         }
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index df6533a..241895c 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -66,14 +66,18 @@
 
 
 
-    // Code below generated by codegen v1.0.0.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AsyncNotedAppOp.java
     //
-    // CHECKSTYLE:OFF Generated code
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
 
     /**
      * Creates a new AsyncNotedAppOp.
@@ -83,7 +87,8 @@
      * @param notingUid
      *   Uid that noted the op
      * @param notingPackageName
-     *   Package that noted the op
+     *   Package that noted the op. {@code null} if the package name that noted the op could be not
+     *   be determined (e.g. when the op is noted from native code).
      * @param message
      *   Message associated with the noteOp. This message is set by the app noting the op
      * @param time
@@ -127,7 +132,8 @@
     }
 
     /**
-     * Package that noted the op
+     * Package that noted the op. {@code null} if the package name that noted the op could be not
+     * be determined (e.g. when the op is noted from native code).
      */
     @DataClass.Generated.Member
     public @Nullable String getNotingPackageName() {
@@ -152,7 +158,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
         // boolean fieldNameEquals(AsyncNotedAppOp other) { ... }
         // boolean fieldNameEquals(FieldType otherValue) { ... }
@@ -187,7 +193,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(android.os.Parcel dest, int flags) {
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -205,6 +211,41 @@
     @DataClass.Generated.Member
     public int describeContents() { return 0; }
 
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ AsyncNotedAppOp(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        int opCode = in.readInt();
+        int notingUid = in.readInt();
+        String notingPackageName = (flg & 0x4) == 0 ? null : in.readString();
+        String message = in.readString();
+        long time = in.readLong();
+
+        this.mOpCode = opCode;
+        com.android.internal.util.AnnotationValidations.validate(
+                IntRange.class, null, mOpCode,
+                "from", 0,
+                "to", AppOpsManager._NUM_OP - 1);
+        this.mNotingUid = notingUid;
+        com.android.internal.util.AnnotationValidations.validate(
+                IntRange.class, null, mNotingUid,
+                "from", 0);
+        this.mNotingPackageName = notingPackageName;
+        this.mMessage = message;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mMessage);
+        this.mTime = time;
+        com.android.internal.util.AnnotationValidations.validate(
+                IntRange.class, null, mTime,
+                "from", 0);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
     @DataClass.Generated.Member
     public static final @NonNull Parcelable.Creator<AsyncNotedAppOp> CREATOR
             = new Parcelable.Creator<AsyncNotedAppOp>() {
@@ -214,29 +255,14 @@
         }
 
         @Override
-        @SuppressWarnings({"unchecked", "RedundantCast"})
-        public AsyncNotedAppOp createFromParcel(android.os.Parcel in) {
-            // You can override field unparcelling by defining methods like:
-            // static FieldType unparcelFieldName(Parcel in) { ... }
-
-            byte flg = in.readByte();
-            int opCode = in.readInt();
-            int notingUid = in.readInt();
-            String notingPackageName = (flg & 0x4) == 0 ? null : in.readString();
-            String message = in.readString();
-            long time = in.readLong();
-            return new AsyncNotedAppOp(
-                    opCode,
-                    notingUid,
-                    notingPackageName,
-                    message,
-                    time);
+        public AsyncNotedAppOp createFromParcel(@NonNull android.os.Parcel in) {
+            return new AsyncNotedAppOp(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1566503083973L,
-            codegenVersion = "1.0.0",
+            time = 1571246617363L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
             inputSignatures = "private final @android.annotation.IntRange(from=0L, to=91L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mNotingPackageName\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
     @Deprecated
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c3c383c..8ea1ff5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2330,6 +2330,12 @@
             "android.app.action.ADMIN_POLICY_COMPLIANCE";
 
     /**
+     * Maximum supported password length. Kind-of arbitrary.
+     * @hide
+     */
+    public static final int MAX_PASSWORD_LENGTH = 16;
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
@@ -3233,6 +3239,22 @@
     }
 
     /**
+     * Returns minimum PasswordMetrics that satisfies all admin policies.
+     *
+     * @hide
+     */
+    public PasswordMetrics getPasswordMinimumMetrics(@UserIdInt int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getPasswordMinimumMetrics(userHandle);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Called by an application that is administering the device to set the length of the password
      * history. After setting this, the user will not be able to enter a new password that is the
      * same as any password in the history. Note that the current password will remain until the
@@ -3415,8 +3437,7 @@
         if (!pm.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
             return 0;
         }
-        // Kind-of arbitrary.
-        return 16;
+        return MAX_PASSWORD_LENGTH;
     }
 
     /**
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0da5b7a..7d2c54e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -72,6 +72,8 @@
     void setPasswordMinimumNonLetter(in ComponentName who, int length, boolean parent);
     int getPasswordMinimumNonLetter(in ComponentName who, int userHandle, boolean parent);
 
+    PasswordMetrics getPasswordMinimumMetrics(int userHandle);
+
     void setPasswordHistoryLength(in ComponentName who, int length, boolean parent);
     int getPasswordHistoryLength(in ComponentName who, int userHandle, boolean parent);
 
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 464f75c..d9bfde5 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -16,41 +16,65 @@
 
 package android.app.admin;
 
+import static android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
+import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
+import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LETTERS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LOWER_CASE;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_DIGITS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_LETTER;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_SYMBOLS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
+import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
+import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
+import static com.android.internal.widget.PasswordValidationError.WEAK_CREDENTIAL_TYPE;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.LockPatternUtils.CredentialType;
 import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
 
 /**
  * A class that represents the metrics of a credential that are used to decide whether or not a
- * credential meets the requirements. If the credential is a pattern, only quality matters.
+ * credential meets the requirements.
  *
  * {@hide}
  */
-public class PasswordMetrics implements Parcelable {
+public final class PasswordMetrics implements Parcelable {
+    private static final String TAG = "PasswordMetrics";
+
     // Maximum allowed number of repeated or ordered characters in a sequence before we'll
     // consider it a complex PIN/password.
     public static final int MAX_ALLOWED_SEQUENCE = 3;
 
-    public int quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+    public @CredentialType int credType;
+    // Fields below only make sense when credType is PASSWORD.
     public int length = 0;
     public int letters = 0;
     public int upperCase = 0;
@@ -58,139 +82,62 @@
     public int numeric = 0;
     public int symbols = 0;
     public int nonLetter = 0;
+    public int nonNumeric = 0;
+    // MAX_VALUE is the most relaxed value, any sequence is ok, e.g. 123456789. 4 would forbid it.
+    public int seqLength = Integer.MAX_VALUE;
 
-    public PasswordMetrics() {}
-
-    public PasswordMetrics(int quality) {
-        this.quality = quality;
+    public PasswordMetrics(int credType) {
+        this.credType = credType;
     }
 
-    public PasswordMetrics(int quality, int length) {
-        this.quality = quality;
+    public PasswordMetrics(int credType , int length, int letters, int upperCase, int lowerCase,
+            int numeric, int symbols, int nonLetter, int nonNumeric, int seqLength) {
+        this.credType = credType;
         this.length = length;
-    }
-
-    public PasswordMetrics(int quality, int length, int letters, int upperCase, int lowerCase,
-            int numeric, int symbols, int nonLetter) {
-        this(quality, length);
         this.letters = letters;
         this.upperCase = upperCase;
         this.lowerCase = lowerCase;
         this.numeric = numeric;
         this.symbols = symbols;
         this.nonLetter = nonLetter;
+        this.nonNumeric = nonNumeric;
+        this.seqLength = seqLength;
     }
 
-    private PasswordMetrics(Parcel in) {
-        quality = in.readInt();
-        length = in.readInt();
-        letters = in.readInt();
-        upperCase = in.readInt();
-        lowerCase = in.readInt();
-        numeric = in.readInt();
-        symbols = in.readInt();
-        nonLetter = in.readInt();
-    }
-
-    /** Returns the min quality allowed by {@code complexityLevel}. */
-    public static int complexityLevelToMinQuality(@PasswordComplexity int complexityLevel) {
-        // this would be the quality of the first metrics since mMetrics is sorted in ascending
-        // order of quality
-        return PasswordComplexityBucket
-                .complexityLevelToBucket(complexityLevel).mMetrics[0].quality;
-    }
-
-    /**
-     * Returns a merged minimum {@link PasswordMetrics} requirements that a new password must meet
-     * to fulfil {@code requestedQuality}, {@code requiresNumeric} and {@code
-     * requiresLettersOrSymbols}, which are derived from {@link DevicePolicyManager} requirements,
-     * and {@code complexityLevel}.
-     *
-     * <p>Note that we are taking {@code userEnteredPasswordQuality} into account because there are
-     * more than one set of metrics to meet the minimum complexity requirement and inspecting what
-     * the user has entered can help determine whether the alphabetic or alphanumeric set of metrics
-     * should be used. For example, suppose minimum complexity requires either ALPHABETIC(8+), or
-     * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
-     * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
-     * an alphanumeric password so we would update the min complexity required min length to 6.
-     */
-    public static PasswordMetrics getMinimumMetrics(@PasswordComplexity int complexityLevel,
-            int userEnteredPasswordQuality, int requestedQuality, boolean requiresNumeric,
-            boolean requiresLettersOrSymbols) {
-        int targetQuality = Math.max(
-                userEnteredPasswordQuality,
-                getActualRequiredQuality(
-                        requestedQuality, requiresNumeric, requiresLettersOrSymbols));
-        return getTargetQualityMetrics(complexityLevel, targetQuality);
-    }
-
-    /**
-     * Returns the {@link PasswordMetrics} at {@code complexityLevel} which the metrics quality
-     * is the same as {@code targetQuality}.
-     *
-     * <p>If {@code complexityLevel} does not allow {@code targetQuality}, returns the metrics
-     * with the min quality at {@code complexityLevel}.
-     */
-    // TODO(bernardchau): update tests to test getMinimumMetrics and change this to be private
-    @VisibleForTesting
-    public static PasswordMetrics getTargetQualityMetrics(
-            @PasswordComplexity int complexityLevel, int targetQuality) {
-        PasswordComplexityBucket targetBucket =
-                PasswordComplexityBucket.complexityLevelToBucket(complexityLevel);
-        for (PasswordMetrics metrics : targetBucket.mMetrics) {
-            if (targetQuality == metrics.quality) {
-                return metrics;
-            }
-        }
-        // none of the metrics at complexityLevel has targetQuality, return metrics with min quality
-        // see test case testGetMinimumMetrics_actualRequiredQualityStricter for an example, where
-        // min complexity allows at least NUMERIC_COMPLEX, user has not entered anything yet, and
-        // requested quality is NUMERIC
-        return targetBucket.mMetrics[0];
-    }
-
-    /**
-     * Finds out the actual quality requirement based on whether quality is {@link
-     * DevicePolicyManager#PASSWORD_QUALITY_COMPLEX} and whether digits, letters or symbols are
-     * required.
-     */
-    @VisibleForTesting
-    // TODO(bernardchau): update tests to test getMinimumMetrics and change this to be private
-    public static int getActualRequiredQuality(
-            int requestedQuality, boolean requiresNumeric, boolean requiresLettersOrSymbols) {
-        if (requestedQuality != PASSWORD_QUALITY_COMPLEX) {
-            return requestedQuality;
-        }
-
-        // find out actual password quality from complex requirements
-        if (requiresNumeric && requiresLettersOrSymbols) {
-            return PASSWORD_QUALITY_ALPHANUMERIC;
-        }
-        if (requiresLettersOrSymbols) {
-            return PASSWORD_QUALITY_ALPHABETIC;
-        }
-        if (requiresNumeric) {
-            // cannot specify numeric complex using complex quality so this must be numeric
-            return PASSWORD_QUALITY_NUMERIC;
-        }
-
-        // reaching here means dpm sets quality to complex without specifying any requirements
-        return PASSWORD_QUALITY_UNSPECIFIED;
+    private PasswordMetrics(PasswordMetrics other) {
+        this(other.credType, other.length, other.letters, other.upperCase, other.lowerCase,
+                other.numeric, other.symbols, other.nonLetter, other.nonNumeric, other.seqLength);
     }
 
     /**
      * Returns {@code complexityLevel} or {@link DevicePolicyManager#PASSWORD_COMPLEXITY_NONE}
      * if {@code complexityLevel} is not valid.
+     *
+     * TODO: move to PasswordPolicy
      */
     @PasswordComplexity
     public static int sanitizeComplexityLevel(@PasswordComplexity int complexityLevel) {
-        return PasswordComplexityBucket.complexityLevelToBucket(complexityLevel).mComplexityLevel;
+        switch (complexityLevel) {
+            case PASSWORD_COMPLEXITY_HIGH:
+            case PASSWORD_COMPLEXITY_MEDIUM:
+            case PASSWORD_COMPLEXITY_LOW:
+            case PASSWORD_COMPLEXITY_NONE:
+                return complexityLevel;
+            default:
+                Log.w(TAG, "Invalid password complexity used: " + complexityLevel);
+                return PASSWORD_COMPLEXITY_NONE;
+        }
     }
 
-    public boolean isDefault() {
-        return quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
-                && length == 0 && letters == 0 && upperCase == 0 && lowerCase == 0
-                && numeric == 0 && symbols == 0 && nonLetter == 0;
+    private static boolean hasInvalidCharacters(byte[] password) {
+        // Allow non-control Latin-1 characters only.
+        for (byte b : password) {
+            char c = (char) b;
+            if (c < 32 || c > 127) {
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override
@@ -200,7 +147,7 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(quality);
+        dest.writeInt(credType);
         dest.writeInt(length);
         dest.writeInt(letters);
         dest.writeInt(upperCase);
@@ -208,12 +155,25 @@
         dest.writeInt(numeric);
         dest.writeInt(symbols);
         dest.writeInt(nonLetter);
+        dest.writeInt(nonNumeric);
+        dest.writeInt(seqLength);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<PasswordMetrics> CREATOR
+    public static final @NonNull Parcelable.Creator<PasswordMetrics> CREATOR
             = new Parcelable.Creator<PasswordMetrics>() {
         public PasswordMetrics createFromParcel(Parcel in) {
-            return new PasswordMetrics(in);
+            int credType = in.readInt();
+            int length = in.readInt();
+            int letters = in.readInt();
+            int upperCase = in.readInt();
+            int lowerCase = in.readInt();
+            int numeric = in.readInt();
+            int symbols = in.readInt();
+            int nonLetter = in.readInt();
+            int nonNumeric = in.readInt();
+            int seqLength = in.readInt();
+            return new PasswordMetrics(credType, length, letters, upperCase, lowerCase, numeric,
+                    symbols, nonLetter, nonNumeric, seqLength);
         }
 
         public PasswordMetrics[] newArray(int size) {
@@ -232,9 +192,9 @@
         if (credential.isPassword()) {
             return PasswordMetrics.computeForPassword(credential.getCredential());
         } else if (credential.isPattern())  {
-            return new PasswordMetrics(PASSWORD_QUALITY_SOMETHING);
+            return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
         } else if (credential.isNone()) {
-            return new PasswordMetrics(PASSWORD_QUALITY_UNSPECIFIED);
+            return new PasswordMetrics(CREDENTIAL_TYPE_NONE);
         } else {
             throw new IllegalArgumentException("Unknown credential type " + credential.getType());
         }
@@ -251,16 +211,19 @@
         int numeric = 0;
         int symbols = 0;
         int nonLetter = 0;
+        int nonNumeric = 0;
         final int length = password.length;
         for (byte b : password) {
             switch (categoryChar((char) b)) {
                 case CHAR_LOWER_CASE:
                     letters++;
                     lowerCase++;
+                    nonNumeric++;
                     break;
                 case CHAR_UPPER_CASE:
                     letters++;
                     upperCase++;
+                    nonNumeric++;
                     break;
                 case CHAR_DIGIT:
                     numeric++;
@@ -269,53 +232,14 @@
                 case CHAR_SYMBOL:
                     symbols++;
                     nonLetter++;
+                    nonNumeric++;
                     break;
             }
         }
 
-        // Determine the quality of the password
-        final boolean hasNumeric = numeric > 0;
-        final boolean hasNonNumeric = (letters + symbols) > 0;
-        final int quality;
-        if (hasNonNumeric && hasNumeric) {
-            quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-        } else if (hasNonNumeric) {
-            quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-        } else if (hasNumeric) {
-            quality = maxLengthSequence(password) > MAX_ALLOWED_SEQUENCE
-                    ? DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
-                    : DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
-        } else {
-            quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-        }
-
-        return new PasswordMetrics(
-                quality, length, letters, upperCase, lowerCase, numeric, symbols, nonLetter);
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof PasswordMetrics)) {
-            return false;
-        }
-        PasswordMetrics o = (PasswordMetrics) other;
-        return this.quality == o.quality
-                && this.length == o.length
-                && this.letters == o.letters
-                && this.upperCase == o.upperCase
-                && this.lowerCase == o.lowerCase
-                && this.numeric == o.numeric
-                && this.symbols == o.symbols
-                && this.nonLetter == o.nonLetter;
-    }
-
-    private boolean satisfiesBucket(PasswordMetrics... bucket) {
-        for (PasswordMetrics metrics : bucket) {
-            if (this.quality == metrics.quality) {
-                return this.length >= metrics.length;
-            }
-        }
-        return false;
+        final int seqLength = maxLengthSequence(password);
+        return new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD, length, letters, upperCase, lowerCase,
+                numeric, symbols, nonLetter, nonNumeric, seqLength);
     }
 
     /**
@@ -400,108 +324,394 @@
         }
     }
 
-    /** Determines the {@link PasswordComplexity} of this {@link PasswordMetrics}. */
-    @PasswordComplexity
-    public int determineComplexity() {
-        for (PasswordComplexityBucket bucket : PasswordComplexityBucket.BUCKETS) {
-            if (satisfiesBucket(bucket.mMetrics)) {
-                return bucket.mComplexityLevel;
-            }
+    /**
+     * Returns the weakest metrics that is stricter or equal to all given metrics.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    public static PasswordMetrics merge(List<PasswordMetrics> metrics) {
+        PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+        for (PasswordMetrics m : metrics) {
+            result.maxWith(m);
         }
-        return PASSWORD_COMPLEXITY_NONE;
+
+        return result;
     }
 
     /**
-     * Requirements in terms of {@link PasswordMetrics} for each {@link PasswordComplexity}.
+     * Makes current metric at least as strong as {@code other} in every criterion.
+     *
+     * TODO: move to PasswordPolicy
      */
-    private static class PasswordComplexityBucket {
-        /**
-         * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_HIGH} in terms of
-         * {@link PasswordMetrics}.
-         */
-        private static final PasswordComplexityBucket HIGH =
-                new PasswordComplexityBucket(
-                        PASSWORD_COMPLEXITY_HIGH,
-                        new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */
-                                8),
-                        new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 6),
-                        new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */
-                                6));
+    private void maxWith(PasswordMetrics other) {
+        credType = Math.max(credType, other.credType);
+        if (credType != CREDENTIAL_TYPE_PASSWORD) {
+            return;
+        }
+        length = Math.max(length, other.length);
+        letters = Math.max(letters, other.letters);
+        upperCase = Math.max(upperCase, other.upperCase);
+        lowerCase = Math.max(lowerCase, other.lowerCase);
+        numeric = Math.max(numeric, other.numeric);
+        symbols = Math.max(symbols, other.symbols);
+        nonLetter = Math.max(nonLetter, other.nonLetter);
+        nonNumeric = Math.max(nonNumeric, other.nonNumeric);
+        seqLength = Math.min(seqLength, other.seqLength);
+    }
 
-        /**
-         * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_MEDIUM} in terms of
-         * {@link PasswordMetrics}.
-         */
-        private static final PasswordComplexityBucket MEDIUM =
-                new PasswordComplexityBucket(
-                        PASSWORD_COMPLEXITY_MEDIUM,
-                        new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */
-                                4),
-                        new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 4),
-                        new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */
-                                4));
+    /**
+     * Returns minimum password quality for a given complexity level.
+     *
+     * TODO: this function is used for determining allowed credential types, so it should return
+     * credential type rather than 'quality'.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    public static int complexityLevelToMinQuality(int complexity) {
+        switch (complexity) {
+            case PASSWORD_COMPLEXITY_HIGH:
+            case PASSWORD_COMPLEXITY_MEDIUM:
+                return PASSWORD_QUALITY_NUMERIC_COMPLEX;
+            case PASSWORD_COMPLEXITY_LOW:
+                return PASSWORD_QUALITY_SOMETHING;
+            case PASSWORD_COMPLEXITY_NONE:
+            default:
+                return PASSWORD_QUALITY_UNSPECIFIED;
+        }
+    }
 
-        /**
-         * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_LOW} in terms of
-         * {@link PasswordMetrics}.
-         */
-        private static final PasswordComplexityBucket LOW =
-                new PasswordComplexityBucket(
-                        PASSWORD_COMPLEXITY_LOW,
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC));
-
-        /**
-         * A special bucket to represent {@link DevicePolicyManager#PASSWORD_COMPLEXITY_NONE}.
-         */
-        private static final PasswordComplexityBucket NONE =
-                new PasswordComplexityBucket(PASSWORD_COMPLEXITY_NONE, new PasswordMetrics());
-
-        /** Array containing all buckets from high to low. */
-        private static final PasswordComplexityBucket[] BUCKETS =
-                new PasswordComplexityBucket[] {HIGH, MEDIUM, LOW};
-
-        @PasswordComplexity
-        private final int mComplexityLevel;
-        private final PasswordMetrics[] mMetrics;
-
-        /**
-         * @param metricsArray must be sorted in ascending order of {@link #quality}.
-         */
-        private PasswordComplexityBucket(@PasswordComplexity int complexityLevel,
-                PasswordMetrics... metricsArray) {
-            int previousQuality = PASSWORD_QUALITY_UNSPECIFIED;
-            for (PasswordMetrics metrics : metricsArray) {
-                if (metrics.quality < previousQuality) {
-                    throw new IllegalArgumentException("metricsArray must be sorted in ascending"
-                            + " order of quality");
-                }
-                previousQuality = metrics.quality;
+    /**
+     * Enum representing requirements for each complexity level.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    private enum ComplexityBucket {
+        // Keep ordered high -> low.
+        BUCKET_HIGH(PASSWORD_COMPLEXITY_HIGH) {
+            @Override
+            boolean canHaveSequence() {
+                return false;
             }
 
-            this.mMetrics = metricsArray;
-            this.mComplexityLevel = complexityLevel;
+            @Override
+            int getMinimumLength(boolean containsNonNumeric) {
+                return containsNonNumeric ? 6 : 8;
+            }
 
+            @Override
+            boolean allowsNumericPassword() {
+                return false;
+            }
+
+            @Override
+            boolean allowsCredType(int credType) {
+                return credType == CREDENTIAL_TYPE_PASSWORD;
+            }
+        },
+        BUCKET_MEDIUM(PASSWORD_COMPLEXITY_MEDIUM) {
+            @Override
+            boolean canHaveSequence() {
+                return false;
+            }
+
+            @Override
+            int getMinimumLength(boolean containsNonNumeric) {
+                return 4;
+            }
+
+            @Override
+            boolean allowsNumericPassword() {
+                return false;
+            }
+
+            @Override
+            boolean allowsCredType(int credType) {
+                return credType == CREDENTIAL_TYPE_PASSWORD;
+            }
+        },
+        BUCKET_LOW(PASSWORD_COMPLEXITY_LOW) {
+            @Override
+            boolean canHaveSequence() {
+                return true;
+            }
+
+            @Override
+            int getMinimumLength(boolean containsNonNumeric) {
+                return 0;
+            }
+
+            @Override
+            boolean allowsNumericPassword() {
+                return true;
+            }
+
+            @Override
+            boolean allowsCredType(int credType) {
+                return credType != CREDENTIAL_TYPE_NONE;
+            }
+        },
+        BUCKET_NONE(PASSWORD_COMPLEXITY_NONE) {
+            @Override
+            boolean canHaveSequence() {
+                return true;
+            }
+
+            @Override
+            int getMinimumLength(boolean containsNonNumeric) {
+                return 0;
+            }
+
+            @Override
+            boolean allowsNumericPassword() {
+                return true;
+            }
+
+            @Override
+            boolean allowsCredType(int credType) {
+                return true;
+            }
+        };
+
+        int mComplexityLevel;
+
+        abstract boolean canHaveSequence();
+        abstract int getMinimumLength(boolean containsNonNumeric);
+        abstract boolean allowsNumericPassword();
+        abstract boolean allowsCredType(int credType);
+
+        ComplexityBucket(int complexityLevel) {
+            this.mComplexityLevel = complexityLevel;
         }
 
-        /** Returns the bucket that {@code complexityLevel} represents. */
-        private static PasswordComplexityBucket complexityLevelToBucket(
-                @PasswordComplexity int complexityLevel) {
-            for (PasswordComplexityBucket bucket : BUCKETS) {
+        static ComplexityBucket forComplexity(int complexityLevel) {
+            for (ComplexityBucket bucket : values()) {
                 if (bucket.mComplexityLevel == complexityLevel) {
                     return bucket;
                 }
             }
-            return NONE;
+            throw new IllegalArgumentException("Invalid complexity level: " + complexityLevel);
         }
     }
+
+    /**
+     * Returns whether current metrics satisfies a given complexity bucket.
+     *
+     * TODO: move inside ComplexityBucket.
+     */
+    private boolean satisfiesBucket(ComplexityBucket bucket) {
+        if (!bucket.allowsCredType(credType)) {
+            return false;
+        }
+        if (credType != CREDENTIAL_TYPE_PASSWORD) {
+            return true;
+        }
+        return (bucket.canHaveSequence() || seqLength <= MAX_ALLOWED_SEQUENCE)
+                && length >= bucket.getMinimumLength(nonNumeric > 0 /* hasNonNumeric */);
+    }
+
+    /**
+     * Returns the maximum complexity level satisfied by password with this metrics.
+     *
+     * TODO: move inside ComplexityBucket.
+     */
+    public int determineComplexity() {
+        for (ComplexityBucket bucket : ComplexityBucket.values()) {
+            if (satisfiesBucket(bucket)) {
+                return bucket.mComplexityLevel;
+            }
+        }
+        throw new IllegalStateException("Failed to figure out complexity for a given metrics");
+    }
+
+    /**
+     * Validates password against minimum metrics and complexity.
+     *
+     * @param adminMetrics - minimum metrics to satisfy admin requirements.
+     * @param minComplexity - minimum complexity imposed by the requester.
+     * @param isPin - whether it is PIN that should be only digits
+     * @param password - password to validate.
+     * @return a list of password validation errors. An empty list means the password is OK.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    public static List<PasswordValidationError> validatePassword(
+            PasswordMetrics adminMetrics, int minComplexity, boolean isPin, byte[] password) {
+
+        if (hasInvalidCharacters(password)) {
+            return Collections.singletonList(
+                    new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
+        }
+
+        final PasswordMetrics enteredMetrics = computeForPassword(password);
+        return validatePasswordMetrics(adminMetrics, minComplexity, isPin, enteredMetrics);
+    }
+
+    /**
+     * Validates password metrics against minimum metrics and complexity
+     *
+     * @param adminMetrics - minimum metrics to satisfy admin requirements.
+     * @param minComplexity - minimum complexity imposed by the requester.
+     * @param isPin - whether it is PIN that should be only digits
+     * @param actualMetrics - metrics for password to validate.
+     * @return a list of password validation errors. An empty list means the password is OK.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    public static List<PasswordValidationError> validatePasswordMetrics(
+            PasswordMetrics adminMetrics, int minComplexity, boolean isPin,
+            PasswordMetrics actualMetrics) {
+        final ComplexityBucket bucket = ComplexityBucket.forComplexity(minComplexity);
+
+        // Make sure credential type is satisfactory.
+        // TODO: stop relying on credential type ordering.
+        if (actualMetrics.credType < adminMetrics.credType
+                || !bucket.allowsCredType(actualMetrics.credType)) {
+            return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0));
+        }
+        // TODO: this needs to be modified if CREDENTIAL_TYPE_PIN is added.
+        if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD) {
+            return Collections.emptyList(); // Nothing to check for pattern or none.
+        }
+
+        if (isPin && actualMetrics.nonNumeric > 0) {
+            return Collections.singletonList(
+                    new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
+        }
+
+        final ArrayList<PasswordValidationError> result = new ArrayList<>();
+        if (actualMetrics.length > MAX_PASSWORD_LENGTH) {
+            result.add(new PasswordValidationError(TOO_LONG, MAX_PASSWORD_LENGTH));
+        }
+
+        final PasswordMetrics minMetrics = applyComplexity(adminMetrics, isPin, bucket);
+
+        // Clamp required length between maximum and minimum valid values.
+        minMetrics.length = Math.min(MAX_PASSWORD_LENGTH,
+                Math.max(minMetrics.length, MIN_LOCK_PASSWORD_SIZE));
+        minMetrics.removeOverlapping();
+
+        comparePasswordMetrics(minMetrics, actualMetrics, result);
+
+        return result;
+    }
+
+    /**
+     * TODO: move to PasswordPolicy
+     */
+    private static void comparePasswordMetrics(PasswordMetrics minMetrics,
+            PasswordMetrics actualMetrics, ArrayList<PasswordValidationError> result) {
+        if (actualMetrics.length < minMetrics.length) {
+            result.add(new PasswordValidationError(TOO_SHORT, minMetrics.length));
+        }
+        if (actualMetrics.letters < minMetrics.letters) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_LETTERS, minMetrics.letters));
+        }
+        if (actualMetrics.upperCase < minMetrics.upperCase) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_UPPER_CASE, minMetrics.upperCase));
+        }
+        if (actualMetrics.lowerCase < minMetrics.lowerCase) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_LOWER_CASE, minMetrics.lowerCase));
+        }
+        if (actualMetrics.numeric < minMetrics.numeric) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_DIGITS, minMetrics.numeric));
+        }
+        if (actualMetrics.symbols < minMetrics.symbols) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_SYMBOLS, minMetrics.symbols));
+        }
+        if (actualMetrics.nonLetter < minMetrics.nonLetter) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_NON_LETTER, minMetrics.nonLetter));
+        }
+        if (actualMetrics.nonNumeric < minMetrics.nonNumeric) {
+            result.add(new PasswordValidationError(NOT_ENOUGH_NON_DIGITS, minMetrics.nonNumeric));
+        }
+        if (actualMetrics.seqLength > minMetrics.seqLength) {
+            result.add(new PasswordValidationError(CONTAINS_SEQUENCE, 0));
+        }
+    }
+
+    /**
+     * Drop requirements that are superseded by others, e.g. if it is required to have 5 upper case
+     * letters and 5 lower case letters, there is no need to require minimum number of letters to
+     * be 10 since it will be fulfilled once upper and lower case requirements are fulfilled.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    private void removeOverlapping() {
+        // upperCase + lowerCase can override letters
+        final int indirectLetters = upperCase + lowerCase;
+
+        // numeric + symbols can override nonLetter
+        final int indirectNonLetter = numeric + symbols;
+
+        // letters + symbols can override nonNumeric
+        final int effectiveLetters = Math.max(letters, indirectLetters);
+        final int indirectNonNumeric = effectiveLetters + symbols;
+
+        // letters + nonLetters can override length
+        // numeric + nonNumeric can also override length, so max it with previous.
+        final int effectiveNonLetter = Math.max(nonLetter, indirectNonLetter);
+        final int effectiveNonNumeric = Math.max(nonNumeric, indirectNonNumeric);
+        final int indirectLength = Math.max(effectiveLetters + effectiveNonLetter,
+                numeric + effectiveNonNumeric);
+
+        if (indirectLetters >= letters) {
+            letters = 0;
+        }
+        if (indirectNonLetter >= nonLetter) {
+            nonLetter = 0;
+        }
+        if (indirectNonNumeric >= nonNumeric) {
+            nonNumeric = 0;
+        }
+        if (indirectLength >= length) {
+            length = 0;
+        }
+    }
+
+    /**
+     * Combine minimum metrics, set by admin, complexity set by the requester and actual entered
+     * password metrics to get resulting minimum metrics that the password has to satisfy. Always
+     * returns a new PasswordMetrics object.
+     *
+     * TODO: move to PasswordPolicy
+     */
+    private static PasswordMetrics applyComplexity(
+            PasswordMetrics adminMetrics, boolean isPin, ComplexityBucket bucket) {
+        final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics);
+
+        if (!bucket.canHaveSequence()) {
+            minMetrics.seqLength = Math.min(minMetrics.seqLength, MAX_ALLOWED_SEQUENCE);
+        }
+
+        minMetrics.length = Math.max(minMetrics.length, bucket.getMinimumLength(!isPin));
+
+        if (!isPin && !bucket.allowsNumericPassword()) {
+            minMetrics.nonNumeric = Math.max(minMetrics.nonNumeric, 1);
+        }
+
+        return minMetrics;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        final PasswordMetrics that = (PasswordMetrics) o;
+        return credType == that.credType
+                && length == that.length
+                && letters == that.letters
+                && upperCase == that.upperCase
+                && lowerCase == that.lowerCase
+                && numeric == that.numeric
+                && symbols == that.symbols
+                && nonLetter == that.nonLetter
+                && nonNumeric == that.nonNumeric
+                && seqLength == that.seqLength;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(credType, length, letters, upperCase, lowerCase, numeric, symbols,
+                nonLetter, nonNumeric, seqLength);
+    }
 }
diff --git a/core/java/android/app/admin/PasswordPolicy.java b/core/java/android/app/admin/PasswordPolicy.java
new file mode 100644
index 0000000..13f11ad
--- /dev/null
+++ b/core/java/android/app/admin/PasswordPolicy.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
+/**
+ * {@hide}
+ */
+public class PasswordPolicy {
+    public static final int DEF_MINIMUM_LENGTH = 0;
+    public static final int DEF_MINIMUM_LETTERS = 1;
+    public static final int DEF_MINIMUM_UPPER_CASE = 0;
+    public static final int DEF_MINIMUM_LOWER_CASE = 0;
+    public static final int DEF_MINIMUM_NUMERIC = 1;
+    public static final int DEF_MINIMUM_SYMBOLS = 1;
+    public static final int DEF_MINIMUM_NON_LETTER = 0;
+
+    public int quality = PASSWORD_QUALITY_UNSPECIFIED;
+    public int length = DEF_MINIMUM_LENGTH;
+    public int letters = DEF_MINIMUM_LETTERS;
+    public int upperCase = DEF_MINIMUM_UPPER_CASE;
+    public int lowerCase = DEF_MINIMUM_LOWER_CASE;
+    public int numeric = DEF_MINIMUM_NUMERIC;
+    public int symbols = DEF_MINIMUM_SYMBOLS;
+    public int nonLetter = DEF_MINIMUM_NON_LETTER;
+
+    /**
+     * Returns a minimum password metrics that the password should have to satisfy current policy.
+     */
+    public PasswordMetrics getMinMetrics() {
+        if (quality == PASSWORD_QUALITY_UNSPECIFIED) {
+            return new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+        } else if (quality == PASSWORD_QUALITY_BIOMETRIC_WEAK
+                || quality == PASSWORD_QUALITY_SOMETHING) {
+            return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+        } // quality is NUMERIC or stronger.
+
+        PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+        result.length = length;
+
+        if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+            result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE;
+        } else if (quality == PASSWORD_QUALITY_ALPHABETIC) {
+            result.nonNumeric = 1;
+        } else if (quality == PASSWORD_QUALITY_ALPHANUMERIC) {
+            result.numeric = 1;
+            result.nonNumeric = 1;
+        } else if (quality == PASSWORD_QUALITY_COMPLEX) {
+            result.numeric = numeric;
+            result.letters = letters;
+            result.upperCase = upperCase;
+            result.lowerCase = lowerCase;
+            result.nonLetter = nonLetter;
+            result.symbols = symbols;
+        }
+        return result;
+    }
+}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b3260c4..024afe2 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -154,12 +154,6 @@
     public abstract int[] getIdleUidsForUser(@UserIdInt int userId);
 
     /**
-     * @return True if currently app idle parole mode is on.  This means all idle apps are allow to
-     * run for a short period of time.
-     */
-    public abstract boolean isAppIdleParoleOn();
-
-    /**
      * Sets up a listener for changes to packages being accessed.
      * @param listener A listener within the system process.
      */
@@ -180,12 +174,6 @@
                 boolean idle, int bucket, int reason);
 
         /**
-         * Callback to inform listeners that the parole state has changed. This means apps are
-         * allowed to do work even if they're idle or in a low bucket.
-         */
-        public abstract void onParoleStateChanged(boolean isParoleOn);
-
-        /**
          * Optional callback to inform the listener that the app has transitioned into
          * an active state due to user interaction.
          */
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 9dbfbc7..02b6b3e 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1469,9 +1469,8 @@
      * This method can be called from multiple threads, as described in
      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
      * and Threads</a>.
-     * @param uri The content:// URI of the insertion request. This must not be {@code null}.
+     * @param uri The content:// URI of the insertion request.
      * @param values A set of column_name/value pairs to add to the database.
-     *     This must not be {@code null}.
      * @return The URI for the newly inserted item.
      */
     @Override
@@ -1538,7 +1537,6 @@
      * @param uri The URI to query. This can potentially have a record ID if this
      * is an update request for a specific record.
      * @param values A set of column_name/value pairs to update in the database.
-     *     This must not be {@code null}.
      * @param selection An optional filter to match rows to update.
      * @return the number of rows affected.
      */
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 654b0f7..26c1ec1 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -31,8 +31,8 @@
     void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason,
             String callerPackageName, in AndroidFuture callback);
     void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
-    void restoreRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
-    void restoreDelayedRuntimePermissionBackup(String packageName, in UserHandle user,
+    void stageAndApplyRuntimePermissionsBackup(in UserHandle user, in ParcelFileDescriptor pipe);
+    void applyStagedRuntimePermissionBackup(String packageName, in UserHandle user,
             in AndroidFuture callback);
     void getAppPermissions(String packageName, in AndroidFuture callback);
     void revokeRuntimePermission(String packageName, String permissionName);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 923d9f8..421e29e 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -62,6 +62,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -139,20 +140,6 @@
     }
 
     /**
-     * Callback for delivering the result of {@link #getRuntimePermissionBackup}.
-     *
-     * @hide
-     */
-    public interface OnGetRuntimePermissionBackupCallback {
-        /**
-         * The result for {@link #getRuntimePermissionBackup}.
-         *
-         * @param backup The backup file
-         */
-        void onGetRuntimePermissionsBackup(@NonNull byte[] backup);
-    }
-
-    /**
      * Callback for delivering the result of {@link #getAppPermissions}.
      *
      * @hide
@@ -246,6 +233,24 @@
     }
 
     /**
+     * Throw a {@link SecurityException} if not at least one of the permissions is granted.
+     *
+     * @param requiredPermissions A list of permissions. Any of of them if sufficient to pass the
+     *                            check
+     */
+    private void enforceSomePermissionsGrantedToSelf(@NonNull String... requiredPermissions) {
+        for (String requiredPermission : requiredPermissions) {
+            if (mContext.checkSelfPermission(requiredPermission)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+        }
+
+        throw new SecurityException("At lest one of the following permissions is required: "
+                + Arrays.toString(requiredPermissions));
+    }
+
+    /**
      * Revoke a set of runtime permissions for various apps.
      *
      * @param request The permissions to revoke as {@code Map<packageName, List<permission>>}
@@ -268,11 +273,7 @@
         }
 
         // Check required permission to fail immediately instead of inside the oneway binder call
-        if (mContext.checkSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
-                    + " required");
-        }
+        enforceSomePermissionsGrantedToSelf(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
 
         mRemoteService.postAsync(service -> {
             Bundle bundledizedRequest = new Bundle();
@@ -358,46 +359,61 @@
      *
      * @param user The user to be backed up
      * @param executor Executor on which to invoke the callback
-     * @param callback Callback to receive the result
-     *
-     * @hide
+     * @param callback Callback to receive the result. The resulting backup-file is opaque and no
+     *                 guarantees are made other than that the file can be send to
+     *                 {@link #restoreRuntimePermissionBackup} in this and future versions of
+     *                 Android.
      */
     @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
     public void getRuntimePermissionBackup(@NonNull UserHandle user,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull OnGetRuntimePermissionBackupCallback callback) {
+            @NonNull Consumer<byte[]> callback) {
         checkNotNull(user);
         checkNotNull(executor);
         checkNotNull(callback);
 
+        // Check required permission to fail immediately instead of inside the oneway binder call
+        enforceSomePermissionsGrantedToSelf(Manifest.permission.GET_RUNTIME_PERMISSIONS);
+
         mRemoteService.postAsync(service -> RemoteStream.receiveBytes(remotePipe -> {
             service.getRuntimePermissionBackup(user, remotePipe);
         })).whenCompleteAsync((bytes, err) -> {
             if (err != null) {
                 Log.e(TAG, "Error getting permission backup", err);
-                callback.onGetRuntimePermissionsBackup(EmptyArray.BYTE);
+                callback.accept(EmptyArray.BYTE);
             } else {
-                callback.onGetRuntimePermissionsBackup(bytes);
+                callback.accept(bytes);
             }
         }, executor);
     }
 
     /**
-     * Restore a backup of the runtime permissions.
+     * Restore a {@link #getRuntimePermissionBackup backup-file} of the runtime permissions.
      *
-     * @param backup the backup to restore. The backup is sent asynchronously, hence it should not
-     *               be modified after calling this method.
+     * <p>This might leave some part of the backup-file unapplied if an package mentioned in the
+     * backup-file is not yet installed. It is required that
+     * {@link #applyStagedRuntimePermissionBackup} is called after any package is installed to
+     * apply the rest of the backup-file.
+     *
+     * @param backup the backup-file to restore. The backup is sent asynchronously, hence it should
+     *               not be modified after calling this method.
      * @param user The user to be restore
-     *
-     * @hide
      */
-    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
-    public void restoreRuntimePermissionBackup(@NonNull byte[] backup, @NonNull UserHandle user) {
+    @RequiresPermission(anyOf = {
+            Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+            Manifest.permission.RESTORE_RUNTIME_PERMISSIONS
+    })
+    public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[] backup,
+            @NonNull UserHandle user) {
         checkNotNull(backup);
         checkNotNull(user);
 
+        // Check required permission to fail immediately instead of inside the oneway binder call
+        enforceSomePermissionsGrantedToSelf(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+                Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
+
         mRemoteService.postAsync(service -> RemoteStream.sendBytes(remotePipe -> {
-            service.restoreRuntimePermissionBackup(user, remotePipe);
+            service.stageAndApplyRuntimePermissionsBackup(user, remotePipe);
         }, backup))
                 .whenComplete((nullResult, err) -> {
                     if (err != null) {
@@ -407,17 +423,22 @@
     }
 
     /**
-     * Restore a backup of the runtime permissions that has been delayed.
+     * Restore unapplied parts of a {@link #stageAndApplyRuntimePermissionsBackup previously staged}
+     * backup-file of the runtime permissions.
+     *
+     * <p>This should be called every time after a package is installed until the callback
+     * reports that there is no more unapplied backup left.
      *
      * @param packageName The package that is ready to have it's permissions restored.
-     * @param user The user to restore
+     * @param user The user the package belongs to
      * @param executor Executor to execute the callback on
-     * @param callback Is called with {@code true} iff there is still more delayed backup left
-     *
-     * @hide
+     * @param callback Is called with {@code true} iff there is still more unapplied backup left
      */
-    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
-    public void restoreDelayedRuntimePermissionBackup(@NonNull String packageName,
+    @RequiresPermission(anyOf = {
+            Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+            Manifest.permission.RESTORE_RUNTIME_PERMISSIONS
+    })
+    public void applyStagedRuntimePermissionBackup(@NonNull String packageName,
             @NonNull UserHandle user,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<Boolean> callback) {
@@ -426,13 +447,17 @@
         checkNotNull(executor);
         checkNotNull(callback);
 
+        // Check required permission to fail immediately instead of inside the oneway binder call
+        enforceSomePermissionsGrantedToSelf(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+                Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
+
         mRemoteService.postAsync(service -> {
-            AndroidFuture<Boolean> restoreDelayedRuntimePermissionBackupResult =
+            AndroidFuture<Boolean> applyStagedRuntimePermissionBackupResult =
                     new AndroidFuture<>();
-            service.restoreDelayedRuntimePermissionBackup(packageName, user,
-                    restoreDelayedRuntimePermissionBackupResult);
-            return restoreDelayedRuntimePermissionBackupResult;
-        }).whenCompleteAsync((restoreDelayedRuntimePermissionBackupResult, err) -> {
+            service.applyStagedRuntimePermissionBackup(packageName, user,
+                    applyStagedRuntimePermissionBackupResult);
+            return applyStagedRuntimePermissionBackupResult;
+        }).whenCompleteAsync((applyStagedRuntimePermissionBackupResult, err) -> {
             long token = Binder.clearCallingIdentity();
             try {
                 if (err != null) {
@@ -440,7 +465,7 @@
                     callback.accept(true);
                 } else {
                     callback.accept(
-                            Boolean.TRUE.equals(restoreDelayedRuntimePermissionBackupResult));
+                            Boolean.TRUE.equals(applyStagedRuntimePermissionBackupResult));
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 7363d77..8f765fa 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -54,6 +54,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
@@ -105,31 +106,54 @@
     public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
             @NonNull OutputStream backup, @NonNull Runnable callback);
 
+
+    /**
+     * @deprecated Implement {@link #onStageAndApplyRuntimePermissionsBackup} instead
+     */
+    @Deprecated
+    @BinderThread
+    public void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
+            @NonNull InputStream backup, @NonNull Runnable callback) {
+    }
+
     /**
      * Restore a backup of the runtime permissions.
      *
      * <p>If an app mentioned in the backup is not installed the state should be saved to later
-     * be restored via {@link #onRestoreDelayedRuntimePermissionsBackup}.
+     * be restored via {@link #onApplyStagedRuntimePermissionBackup}.
      *
      * @param user The user to restore
      * @param backup The stream to read the backup from
      * @param callback Callback waiting for operation to be complete
      */
     @BinderThread
-    public abstract void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
-            @NonNull InputStream backup, @NonNull Runnable callback);
+    public void onStageAndApplyRuntimePermissionsBackup(@NonNull UserHandle user,
+            @NonNull InputStream backup, @NonNull Runnable callback) {
+        onRestoreRuntimePermissionsBackup(user, backup, callback);
+    }
+
+    /**
+     * @deprecated Implement {@link #onApplyStagedRuntimePermissionBackup} instead
+     */
+    @Deprecated
+    @BinderThread
+    public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
+            @NonNull UserHandle user, @NonNull Consumer<Boolean> callback) {
+    }
 
     /**
      * Restore the permission state of an app that was provided in
-     * {@link #onRestoreRuntimePermissionsBackup} but could not be restored back then.
+     * {@link #onStageAndApplyRuntimePermissionsBackup} but could not be restored back then.
      *
      * @param packageName The app to restore
      * @param user The user to restore
      * @param callback Callback waiting for whether there is still delayed backup left
      */
     @BinderThread
-    public abstract void onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
-            @NonNull UserHandle user, @NonNull Consumer<Boolean> callback);
+    public void onApplyStagedRuntimePermissionBackup(@NonNull String packageName,
+            @NonNull UserHandle user, @NonNull Consumer<Boolean> callback) {
+        onRestoreDelayedRuntimePermissionsBackup(packageName, user, callback);
+    }
 
     /**
      * Gets the runtime permissions for an app.
@@ -238,7 +262,8 @@
                     request.put(packageName, permissions);
                 }
 
-                enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(
+                        Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
 
                 // Verify callerPackageName
                 try {
@@ -258,12 +283,33 @@
                         });
             }
 
+            /**
+             * Throw a {@link SecurityException} if not at least one of the permissions is granted.
+             *
+             * @param requiredPermissions A list of permissions. Any of of them if sufficient to
+             *                            pass the check
+             */
+            private void enforceSomePermissionsGrantedToCaller(
+                    @NonNull String... requiredPermissions) {
+                for (String requiredPermission : requiredPermissions) {
+                    if (checkCallingPermission(requiredPermission)
+                            == PackageManager.PERMISSION_GRANTED) {
+                        return;
+                    }
+                }
+
+                throw new SecurityException(
+                        "At lest one of the following permissions is required: " + Arrays.toString(
+                                requiredPermissions));
+            }
+
+
             @Override
             public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
                 checkNotNull(user);
                 checkNotNull(pipe);
 
-                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
 
                 try (OutputStream backup = new ParcelFileDescriptor.AutoCloseOutputStream(pipe)) {
                     CountDownLatch latch = new CountDownLatch(1);
@@ -277,15 +323,17 @@
             }
 
             @Override
-            public void restoreRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
+            public void stageAndApplyRuntimePermissionsBackup(UserHandle user,
+                    ParcelFileDescriptor pipe) {
                 checkNotNull(user);
                 checkNotNull(pipe);
 
-                enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+                        Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
 
                 try (InputStream backup = new ParcelFileDescriptor.AutoCloseInputStream(pipe)) {
                     CountDownLatch latch = new CountDownLatch(1);
-                    onRestoreRuntimePermissionsBackup(user, backup, latch::countDown);
+                    onStageAndApplyRuntimePermissionsBackup(user, backup, latch::countDown);
                     latch.await();
                 } catch (IOException e) {
                     Log.e(LOG_TAG, "Could not open pipe to read backup from", e);
@@ -295,15 +343,16 @@
             }
 
             @Override
-            public void restoreDelayedRuntimePermissionBackup(String packageName, UserHandle user,
+            public void applyStagedRuntimePermissionBackup(String packageName, UserHandle user,
                     AndroidFuture callback) {
                 checkNotNull(packageName);
                 checkNotNull(user);
                 checkNotNull(callback);
 
-                enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+                        Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
 
-                onRestoreDelayedRuntimePermissionsBackup(packageName, user, callback::complete);
+                onApplyStagedRuntimePermissionBackup(packageName, user, callback::complete);
             }
 
             @Override
@@ -311,7 +360,7 @@
                 checkNotNull(packageName, "packageName");
                 checkNotNull(callback, "callback");
 
-                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
 
                 onGetAppPermissions(packageName, callback::complete);
             }
@@ -321,7 +370,8 @@
                 checkNotNull(packageName, "packageName");
                 checkNotNull(permissionName, "permissionName");
 
-                enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(
+                        Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
 
                 CountDownLatch latch = new CountDownLatch(1);
                 PermissionControllerService.this.onRevokeRuntimePermission(packageName,
@@ -340,7 +390,7 @@
                 checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED);
                 checkNotNull(callback, "callback");
 
-                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
 
                 onCountPermissionApps(permissionNames, flags, callback::complete);
             }
@@ -351,7 +401,7 @@
                 checkArgumentNonnegative(numMillis);
                 checkNotNull(callback, "callback");
 
-                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+                enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
 
                 onGetPermissionUsages(countSystem, numMillis, callback::complete);
             }
@@ -369,15 +419,17 @@
                 checkNotNull(callback);
 
                 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
-                    enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+                    enforceSomePermissionsGrantedToCaller(
+                            Manifest.permission.GRANT_RUNTIME_PERMISSIONS);
                 }
 
                 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
-                    enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+                    enforceSomePermissionsGrantedToCaller(
+                            Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
                 }
 
-                enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
-                        null);
+                enforceSomePermissionsGrantedToCaller(
+                        Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
 
                 onSetRuntimePermissionGrantStateByDeviceAdmin(callerPackageName,
                         packageName, permission, grantState, callback::complete);
@@ -387,8 +439,8 @@
             public void grantOrUpgradeDefaultRuntimePermissions(@NonNull AndroidFuture callback) {
                 checkNotNull(callback, "callback");
 
-                enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
-                        null);
+                enforceSomePermissionsGrantedToCaller(
+                        Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
 
                 onGrantOrUpgradeDefaultRuntimePermissions(() -> callback.complete(true));
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 457dcc0..800c15c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8241,20 +8241,6 @@
         public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled";
 
         /**
-         * The settings values which should only be restored if the target device is the
-         * same as the source device
-         *
-         * NOTE: Settings are backed up and restored in the order they appear
-         *       in this array. If you have one setting depending on another,
-         *       make sure that they are ordered appropriately.
-         *
-         * @hide
-         */
-        public static final String[] DEVICE_SPECIFIC_SETTINGS_TO_BACKUP = {
-                DISPLAY_DENSITY_FORCED,
-        };
-
-        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
@@ -10877,16 +10863,13 @@
          * App standby (app idle) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          * <p>
-         * "idle_duration=5000,parole_interval=4500,screen_thresholds=0/0/60000/120000"
+         * "idle_duration=5000,prediction_timeout=4500,screen_thresholds=0/0/60000/120000"
          * <p>
          * All durations are in millis.
          * Array values are separated by forward slashes
          * The following keys are supported:
          *
          * <pre>
-         * parole_interval                  (long)
-         * parole_window                    (long)
-         * parole_duration                  (long)
          * screen_thresholds                (long[4])
          * elapsed_thresholds               (long[4])
          * strong_usage_duration            (long)
@@ -10897,17 +10880,12 @@
          * exempted_sync_duration           (long)
          * system_interaction_duration      (long)
          * initial_foreground_service_start_duration (long)
-         * stable_charging_threshold        (long)
-         *
-         * idle_duration        (long) // This is deprecated and used to circumvent b/26355386.
-         * idle_duration2       (long) // deprecated
-         * wallclock_threshold  (long) // deprecated
          * </pre>
          *
          * <p>
          * Type: string
          * @hide
-         * @see com.android.server.usage.UsageStatsService.SettingsObserver
+         * @see com.android.server.usage.AppStandbyController
          */
         public static final String APP_IDLE_CONSTANTS = "app_idle_constants";
 
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index f1c870d..dd2586c 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -126,11 +126,29 @@
             = "android.service.quicksettings.ACTIVE_TILE";
 
     /**
+     * Meta-data for a tile to support {@code BooleanState}.
+     * <p>
+     * BooleanState is for tiles that should support switch tile behavior in accessibility. This is
+     * the behavior of most of the framework tiles.
+     *
+     * To make a TileService support BooleanState, set this meta-data to true on the TileService's
+     * manifest declaration.
+     * <pre class="prettyprint">
+     * {@literal
+     * <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+     *      android:value="true" />
+     * }
+     * </pre>
+     */
+    public static final String META_DATA_BOOLEAN_TILE =
+            "android.service.quicksettings.BOOLEAN_TILE";
+
+    /**
      * Used to notify SysUI that Listening has be requested.
      * @hide
      */
-    public static final String ACTION_REQUEST_LISTENING
-            = "android.service.quicksettings.action.REQUEST_LISTENING";
+    public static final String ACTION_REQUEST_LISTENING =
+            "android.service.quicksettings.action.REQUEST_LISTENING";
 
     /**
      * @hide
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0817452..cc28840 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -707,10 +707,10 @@
         try {
             services = service.getEnabledAccessibilityServiceList(feedbackTypeFlags, userId);
             if (DEBUG) {
-                Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+                Log.i(LOG_TAG, "Enabled AccessibilityServices " + services);
             }
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
+            Log.e(LOG_TAG, "Error while obtaining the enabled AccessibilityServices. ", re);
         }
         if (mAccessibilityPolicy != null) {
             services = mAccessibilityPolicy.getEnabledAccessibilityServiceList(
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 158700b..363e549 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -184,6 +184,12 @@
         System.loadLibrary("android");
         System.loadLibrary("compiler_rt");
         System.loadLibrary("jnigraphics");
+
+        try {
+            System.loadLibrary("sfplugin_ccodec");
+        } catch (Error | RuntimeException e) {
+            // tolerate missing sfplugin_ccodec which is only present on Codec 2 devices
+        }
     }
 
     native private static void nativePreloadAppProcessHALs();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 1daa25a..8fea703 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -30,6 +30,7 @@
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.PasswordMetrics;
 import android.app.trust.IStrongAuthTracker;
 import android.app.trust.TrustManager;
 import android.content.ComponentName;
@@ -58,10 +59,10 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 
-import com.google.android.collect.Lists;
-
 import libcore.util.HexEncoding;
 
+import com.google.android.collect.Lists;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.security.MessageDigest;
@@ -77,7 +78,6 @@
  * Utilities for the lock pattern and its settings.
  */
 public class LockPatternUtils {
-
     private static final String TAG = "LockPatternUtils";
     private static final boolean FRP_CREDENTIAL_ENABLED = true;
 
@@ -114,6 +114,7 @@
      */
     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
 
+    // NOTE: When modifying this, make sure credential sufficiency validation logic is intact.
     public static final int CREDENTIAL_TYPE_NONE = -1;
     public static final int CREDENTIAL_TYPE_PATTERN = 1;
     public static final int CREDENTIAL_TYPE_PASSWORD = 2;
@@ -289,10 +290,10 @@
         return getDevicePolicyManager().getPasswordMaximumLength(quality);
     }
 
-    /**
-     * Gets the device policy password mode. If the mode is non-specific, returns
-     * MODE_PATTERN which allows the user to choose anything.
-     */
+    public PasswordMetrics getRequestedPasswordMetrics(int userId) {
+        return getDevicePolicyManager().getPasswordMinimumMetrics(userId);
+    }
+
     public int getRequestedPasswordQuality(int userId) {
         return getDevicePolicyManager().getPasswordQuality(null, userId);
     }
diff --git a/core/java/com/android/internal/widget/PasswordValidationError.java b/core/java/com/android/internal/widget/PasswordValidationError.java
new file mode 100644
index 0000000..41b234e
--- /dev/null
+++ b/core/java/com/android/internal/widget/PasswordValidationError.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+/**
+ * Password validation error containing an error code and optional requirement.
+ */
+public class PasswordValidationError {
+    // Password validation error codes
+    public static final int WEAK_CREDENTIAL_TYPE = 1;
+    public static final int CONTAINS_INVALID_CHARACTERS = 2;
+    public static final int TOO_SHORT = 3;
+    public static final int TOO_LONG = 4;
+    public static final int CONTAINS_SEQUENCE = 5;
+    public static final int NOT_ENOUGH_LETTERS = 6;
+    public static final int NOT_ENOUGH_UPPER_CASE = 7;
+    public static final int NOT_ENOUGH_LOWER_CASE = 8;
+    public static final int NOT_ENOUGH_DIGITS = 9;
+    public static final int NOT_ENOUGH_SYMBOLS = 10;
+    public static final int NOT_ENOUGH_NON_LETTER = 11;
+    public static final int NOT_ENOUGH_NON_DIGITS = 12;
+    public static final int RECENTLY_USED = 13;
+    // WARNING: if you add a new error, make sure it is presented to the user correctly in Settings.
+
+    public final int errorCode;
+    public final int requirement;
+
+    public PasswordValidationError(int errorCode) {
+        this(errorCode, 0);
+    }
+
+    public PasswordValidationError(int errorCode, int requirement) {
+        this.errorCode = errorCode;
+        this.requirement = requirement;
+    }
+
+    @Override
+    public String toString() {
+        return errorCodeToString(errorCode) + (requirement > 0 ? "; required: " + requirement : "");
+    }
+
+    /**
+     * Returns textual representation of the error for logging purposes.
+     */
+    private static String errorCodeToString(int error) {
+        switch (error) {
+            case WEAK_CREDENTIAL_TYPE: return "Weak credential type";
+            case CONTAINS_INVALID_CHARACTERS: return "Contains an invalid character";
+            case TOO_SHORT: return "Password too short";
+            case TOO_LONG: return "Password too long";
+            case CONTAINS_SEQUENCE: return "Sequence too long";
+            case NOT_ENOUGH_LETTERS: return "Too few letters";
+            case NOT_ENOUGH_UPPER_CASE: return "Too few upper case letters";
+            case NOT_ENOUGH_LOWER_CASE: return "Too few lower case letters";
+            case NOT_ENOUGH_DIGITS: return "Too few numeric characters";
+            case NOT_ENOUGH_SYMBOLS: return "Too few symbols";
+            case NOT_ENOUGH_NON_LETTER: return "Too few non-letter characters";
+            case NOT_ENOUGH_NON_DIGITS: return "Too few non-numeric characters";
+            case RECENTLY_USED: return "Pin or password was recently used";
+            default: return "Unknown error " + error;
+        }
+    }
+
+}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0fada1b..49c5cad 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -35,7 +35,6 @@
 #include <limits>
 #include <memory>
 #include <string>
-#include <unordered_map>
 #include <vector>
 
 #include "core_jni_helpers.h"
@@ -62,45 +61,26 @@
 
 using namespace android;
 
-static const bool kDebugPolicy = false;
-static const bool kDebugProc = false;
+static constexpr bool kDebugPolicy = false;
+static constexpr bool kDebugProc = false;
 
 // Stack reservation for reading small proc files.  Most callers of
 // readProcFile() are reading files under this threshold, e.g.,
 // /proc/pid/stat.  /proc/pid/time_in_state ends up being about 520
 // bytes, so use 1024 for the stack to provide a bit of slack.
-static const ssize_t kProcReadStackBufferSize = 1024;
+static constexpr ssize_t kProcReadStackBufferSize = 1024;
 
 // The other files we read from proc tend to be a bit larger (e.g.,
 // /proc/stat is about 3kB), so once we exhaust the stack buffer,
 // retry with a relatively large heap-allocated buffer.  We double
 // this size and retry until the whole file fits.
-static const ssize_t kProcReadMinHeapBufferSize = 4096;
+static constexpr ssize_t kProcReadMinHeapBufferSize = 4096;
 
 #if GUARD_THREAD_PRIORITY
 Mutex gKeyCreateMutex;
 static pthread_key_t gBgKey = -1;
 #endif
 
-/*
- *  cpuset/sched aggregate profile mappings
- */
-static const std::unordered_map<int, std::string> kCpusetProfileMap = {
-    {SP_DEFAULT, "CPUSET_SP_DEFAULT"}, {SP_BACKGROUND, "CPUSET_SP_BACKGROUND"},
-    {SP_FOREGROUND, "CPUSET_SP_FOREGROUND"},{SP_SYSTEM, "CPUSET_SP_SYSTEM"},
-    {SP_AUDIO_APP, "CPUSET_SP_FOREGROUND"}, {SP_AUDIO_SYS, "CPUSET_SP_FOREGROUND"},
-    {SP_TOP_APP, "CPUSET_SP_TOP_APP"}, {SP_RT_APP, "CPUSET_SP_DEFAULT"},
-    {SP_RESTRICTED, "CPUSET_SP_RESTRICTED"}
-};
-
-static const std::unordered_map<int, std::string> kSchedProfileMap = {
-    {SP_DEFAULT, "SCHED_SP_DEFAULT"}, {SP_BACKGROUND, "SCHED_SP_BACKGROUND"},
-    {SP_FOREGROUND, "SCHED_SP_FOREGROUND"}, {SP_SYSTEM, "SCHED_SP_DEFAULT"},
-    {SP_AUDIO_APP, "SCHED_SP_FOREGROUND"}, {SP_AUDIO_SYS, "SCHED_SP_FOREGROUND"},
-    {SP_TOP_APP, "SCHED_SP_TOP_APP"}, {SP_RT_APP, "SCHED_SP_RT_APP"},
-    {SP_RESTRICTED, "SCHED_SP_DEFAULT"}
-};
-
 // For both of these, err should be in the errno range (positive), not a status_t (negative)
 static void signalExceptionForError(JNIEnv* env, int err, int tid) {
     switch (err) {
@@ -227,7 +207,7 @@
         return;
     }
 
-    int res = SetTaskProfiles(tid, {kSchedProfileMap.at(grp)}, true) ? 0 : -1;
+    int res = SetTaskProfiles(tid, {get_sched_policy_name((SchedPolicy)grp)}, true) ? 0 : -1;
 
     if (res != NO_ERROR) {
         signalExceptionForGroupError(env, -res, tid);
@@ -241,7 +221,7 @@
         return;
     }
 
-    int res = SetTaskProfiles(tid, {kCpusetProfileMap.at(grp)}, true) ? 0 : -1;
+    int res = SetTaskProfiles(tid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true) ? 0 : -1;
 
     if (res != NO_ERROR) {
         signalExceptionForGroupError(env, -res, tid);
@@ -328,7 +308,7 @@
             if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
                 // This task wants to stay at background
                 // update its cpuset so it doesn't only run on bg core(s)
-                err = SetTaskProfiles(t_pid, {kCpusetProfileMap.at(grp)}, true) ? 0 : -1;
+                err = SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true) ? 0 : -1;
                 if (err != NO_ERROR) {
                     signalExceptionForGroupError(env, -err, t_pid);
                     break;
@@ -337,7 +317,7 @@
             }
         }
 
-        err = SetTaskProfiles(t_pid, {kCpusetProfileMap.at(grp)}, true) ? 0 : -1;
+        err = SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true) ? 0 : -1;
         if (err != NO_ERROR) {
             signalExceptionForGroupError(env, -err, t_pid);
             break;
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 15b98af..06040a5 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -43,7 +43,7 @@
     reserved 15; // next_heartbeat
     reserved 16; // last_heartbeat_time_millis
     reserved 17; // next_heartbeat_time_millis
-    optional bool in_parole = 18;
+    reserved 18; // in_parole
     optional bool in_thermal = 19;
 
     repeated int32 started_users = 2;
@@ -534,7 +534,7 @@
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
         optional bool is_charging = 1;
-        optional bool is_in_parole = 2;
+        reserved 2; // is_in_parole
         optional int64 elapsed_realtime = 6;
 
         // List of UIDs currently in the foreground.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5c1e13b..f98ea2c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3511,6 +3511,13 @@
     <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
                 android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows the system to restore runtime permission state. This might grant
+    permissions, hence this is a more scoped, less powerful variant of GRANT_RUNTIME_PERMISSIONS.
+    Among other restrictions this cannot override user choices.
+    @hide -->
+    <permission android:name="android.permission.RESTORE_RUNTIME_PERMISSIONS"
+                android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to change policy_fixed permissions.
     @hide -->
     <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 14f5d97..acaaeec 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3701,6 +3701,8 @@
             <flag name="flagRequestFingerprintGestures" value="0x00000200" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. -->
             <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_HANDLE_SHORTCUT}. -->
+            <flag name="flagHandleShortcut" value="0x00000800" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5605246..11efabb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -758,6 +758,9 @@
     <!-- Indicates that p2p MAC randomization is supported on this device -->
     <bool translatable="false" name="config_wifi_p2p_mac_randomization_supported">false</bool>
 
+    <!-- Indicates that AP mode MAC randomization is supported on this device -->
+    <bool translatable="false" name="config_wifi_ap_mac_randomization_supported">true</bool>
+
     <!-- flag for activating paranoid MAC randomization on a limited set of SSIDs -->
     <bool translatable="false" name="config_wifi_aggressive_randomization_ssid_whitelist_enabled">false</bool>
 
@@ -4319,11 +4322,11 @@
 
     <!-- Trigger a warning for notifications with RemoteView objects that are larger in bytes than
     this value (default 1MB)-->
-    <integer name="config_notificationWarnRemoteViewSizeBytes">1000000</integer>
+    <integer name="config_notificationWarnRemoteViewSizeBytes">2000000</integer>
 
     <!-- Strip notification RemoteView objects that are larger in bytes than this value (also log)
     (default 2MB) -->
-    <integer name="config_notificationStripRemoteViewSizeBytes">2000000</integer>
+    <integer name="config_notificationStripRemoteViewSizeBytes">5000000</integer>
 
     <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission
          grants, even if the UICC claims that the app should be privileged. See b/138150105 -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 42cd2cd..6371d80 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1970,6 +1970,7 @@
   <java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" />
   <java-symbol type="bool" name="config_wifi_connected_mac_randomization_supported" />
   <java-symbol type="bool" name="config_wifi_p2p_mac_randomization_supported" />
+  <java-symbol type="bool" name="config_wifi_ap_mac_randomization_supported" />
   <java-symbol type="bool" name="config_wifi_aggressive_randomization_ssid_whitelist_enabled" />
   <java-symbol type="bool" name="config_wifi_link_probing_supported" />
   <java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 4ae9494..fb0dd46 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -20,52 +20,44 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 import static android.app.admin.PasswordMetrics.complexityLevelToMinQuality;
-import static android.app.admin.PasswordMetrics.getActualRequiredQuality;
-import static android.app.admin.PasswordMetrics.getMinimumMetrics;
-import static android.app.admin.PasswordMetrics.getTargetQualityMetrics;
 import static android.app.admin.PasswordMetrics.sanitizeComplexityLevel;
+import static android.app.admin.PasswordMetrics.validatePasswordMetrics;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.widget.PasswordValidationError;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
 /** Unit tests for {@link PasswordMetrics}. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
+@Presubmit
 public class PasswordMetricsTest {
-
-    @Test
-    public void testIsDefault() {
-        final PasswordMetrics metrics = new PasswordMetrics();
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, metrics.quality);
-        assertEquals(0, metrics.length);
-        assertEquals(0, metrics.letters);
-        assertEquals(0, metrics.upperCase);
-        assertEquals(0, metrics.lowerCase);
-        assertEquals(0, metrics.numeric);
-        assertEquals(0, metrics.symbols);
-        assertEquals(0, metrics.nonLetter);
-    }
-
     @Test
     public void testParceling() {
-        final int quality = 0;
+        final int credType = CREDENTIAL_TYPE_PASSWORD;
         final int length = 1;
         final int letters = 2;
         final int upperCase = 3;
@@ -73,20 +65,21 @@
         final int numeric = 5;
         final int symbols = 6;
         final int nonLetter = 7;
+        final int nonNumeric = 8;
+        final int seqLength = 9;
 
         final Parcel parcel = Parcel.obtain();
-        final PasswordMetrics metrics;
+        PasswordMetrics metrics = new PasswordMetrics(credType, length, letters, upperCase,
+                lowerCase, numeric, symbols, nonLetter, nonNumeric, seqLength);
         try {
-            new PasswordMetrics(
-                    quality, length, letters, upperCase, lowerCase, numeric, symbols, nonLetter)
-                    .writeToParcel(parcel, 0);
+            metrics.writeToParcel(parcel, 0);
             parcel.setDataPosition(0);
             metrics = PasswordMetrics.CREATOR.createFromParcel(parcel);
         } finally {
             parcel.recycle();
         }
 
-        assertEquals(quality, metrics.quality);
+        assertEquals(credType, metrics.credType);
         assertEquals(length, metrics.length);
         assertEquals(letters, metrics.letters);
         assertEquals(upperCase, metrics.upperCase);
@@ -94,7 +87,8 @@
         assertEquals(numeric, metrics.numeric);
         assertEquals(symbols, metrics.symbols);
         assertEquals(nonLetter, metrics.nonLetter);
-
+        assertEquals(nonNumeric, metrics.nonNumeric);
+        assertEquals(seqLength, metrics.seqLength);
     }
 
     @Test
@@ -111,23 +105,6 @@
     }
 
     @Test
-    public void testComputeForPassword_quality() {
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
-                PasswordMetrics.computeForPassword("a1".getBytes()).quality);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
-                PasswordMetrics.computeForPassword("a".getBytes()).quality);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
-                PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
-                PasswordMetrics.computeForPassword("1".getBytes()).quality);
-        // contains a long sequence so isn't complex
-        assertEquals(PASSWORD_QUALITY_NUMERIC,
-                PasswordMetrics.computeForPassword("1234".getBytes()).quality);
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                PasswordMetrics.computeForPassword("".getBytes()).quality);
-    }
-
-    @Test
     public void testMaxLengthSequence() {
         assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes()));
         assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes()));
@@ -142,69 +119,15 @@
     }
 
     @Test
-    public void testEquals() {
-        PasswordMetrics metrics0 = new PasswordMetrics();
-        PasswordMetrics metrics1 = new PasswordMetrics();
-        assertNotEquals(metrics0, null);
-        assertNotEquals(metrics0, new Object());
-        assertEquals(metrics0, metrics0);
-        assertEquals(metrics0, metrics1);
-
-        assertEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
-                new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4));
-
-        assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
-                new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 5));
-
-        assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
-                new PasswordMetrics(PASSWORD_QUALITY_COMPLEX, 4));
-
-        metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
-        metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
-        assertEquals(metrics0, metrics1);
-        metrics1.letters++;
-        assertNotEquals(metrics0, metrics1);
-        metrics1.letters--;
-        metrics1.upperCase++;
-        assertNotEquals(metrics0, metrics1);
-        metrics1.upperCase--;
-        metrics1.lowerCase++;
-        assertNotEquals(metrics0, metrics1);
-        metrics1.lowerCase--;
-        metrics1.numeric++;
-        assertNotEquals(metrics0, metrics1);
-        metrics1.numeric--;
-        metrics1.symbols++;
-        assertNotEquals(metrics0, metrics1);
-        metrics1.symbols--;
-        metrics1.nonLetter++;
-        assertNotEquals(metrics0, metrics1);
-        metrics1.nonLetter--;
-        assertEquals(metrics0, metrics1);
-
-
-    }
-
-    @Test
-    public void testConstructQuality() {
-        PasswordMetrics expected = new PasswordMetrics();
-        expected.quality = PASSWORD_QUALITY_COMPLEX;
-
-        PasswordMetrics actual = new PasswordMetrics(PASSWORD_QUALITY_COMPLEX);
-
-        assertEquals(expected, actual);
-    }
-
-    @Test
     public void testDetermineComplexity_none() {
         assertEquals(PASSWORD_COMPLEXITY_NONE,
-                PasswordMetrics.computeForPassword("".getBytes()).determineComplexity());
+                new PasswordMetrics(CREDENTIAL_TYPE_NONE).determineComplexity());
     }
 
     @Test
     public void testDetermineComplexity_lowSomething() {
         assertEquals(PASSWORD_COMPLEXITY_LOW,
-                new PasswordMetrics(PASSWORD_QUALITY_SOMETHING).determineComplexity());
+                new PasswordMetrics(CREDENTIAL_TYPE_PATTERN).determineComplexity());
     }
 
     @Test
@@ -324,122 +247,84 @@
     }
 
     @Test
-    public void testGetTargetQualityMetrics_noneComplexityReturnsDefaultMetrics() {
-        PasswordMetrics metrics =
-                getTargetQualityMetrics(PASSWORD_COMPLEXITY_NONE, PASSWORD_QUALITY_ALPHANUMERIC);
-
-        assertTrue(metrics.isDefault());
+    public void testMerge_single() {
+        PasswordMetrics metrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+        assertEquals(CREDENTIAL_TYPE_PASSWORD,
+                PasswordMetrics.merge(Collections.singletonList(metrics)).credType);
     }
 
     @Test
-    public void testGetTargetQualityMetrics_qualityNotAllowedReturnsMinQualityMetrics() {
-        PasswordMetrics metrics =
-                getTargetQualityMetrics(PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_NUMERIC);
-
-        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
-        assertEquals(/* expected= */ 4, metrics.length);
+    public void testMerge_credentialTypes() {
+        PasswordMetrics none = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+        PasswordMetrics pattern = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+        PasswordMetrics password = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
+        assertEquals(CREDENTIAL_TYPE_PATTERN,
+                PasswordMetrics.merge(Arrays.asList(new PasswordMetrics[]{none, pattern}))
+                        .credType);
+        assertEquals(CREDENTIAL_TYPE_PASSWORD,
+                PasswordMetrics.merge(Arrays.asList(new PasswordMetrics[]{none, password}))
+                        .credType);
+        assertEquals(CREDENTIAL_TYPE_PASSWORD,
+                PasswordMetrics.merge(Arrays.asList(new PasswordMetrics[]{password, pattern}))
+                        .credType);
     }
 
     @Test
-    public void testGetTargetQualityMetrics_highComplexityNumericComplex() {
-        PasswordMetrics metrics = getTargetQualityMetrics(
-                PASSWORD_COMPLEXITY_HIGH, PASSWORD_QUALITY_NUMERIC_COMPLEX);
+    public void testValidatePasswordMetrics_credentialTypes() {
+        PasswordMetrics none = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+        PasswordMetrics pattern = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+        PasswordMetrics password = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
 
-        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
-        assertEquals(/* expected= */ 8, metrics.length);
+        // To pass minimal length check.
+        password.length = 4;
+
+        // No errors expected, credential is of stronger or equal type.
+        assertValidationErrors(
+                validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, none));
+        assertValidationErrors(
+                validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, pattern));
+        assertValidationErrors(
+                validatePasswordMetrics(none, PASSWORD_COMPLEXITY_NONE, false, password));
+        assertValidationErrors(
+                validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, pattern));
+        assertValidationErrors(
+                validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, password));
+        assertValidationErrors(
+                validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, password));
+
+        // Now actual credential type is weaker than required:
+        assertValidationErrors(
+                validatePasswordMetrics(pattern, PASSWORD_COMPLEXITY_NONE, false, none),
+                PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
+        assertValidationErrors(
+                validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, none),
+                PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
+        assertValidationErrors(
+                validatePasswordMetrics(password, PASSWORD_COMPLEXITY_NONE, false, pattern),
+                PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
     }
 
-    @Test
-    public void testGetTargetQualityMetrics_mediumComplexityAlphabetic() {
-        PasswordMetrics metrics = getTargetQualityMetrics(
-                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_ALPHABETIC);
+    /**
+     * @param expected sequense of validation error codes followed by requirement values, must have
+     *                even number of elements. Empty means no errors.
+     */
+    private void assertValidationErrors(
+            List<PasswordValidationError> actualErrors, int... expected) {
+        assertEquals("Test programming error: content shoud have even number of elements",
+                0, expected.length % 2);
+        assertEquals("wrong number of validation errors", expected.length / 2, actualErrors.size());
+        HashMap<Integer, Integer> errorMap = new HashMap<>();
+        for (PasswordValidationError error : actualErrors) {
+            errorMap.put(error.errorCode, error.requirement);
+        }
 
-        assertEquals(PASSWORD_QUALITY_ALPHABETIC, metrics.quality);
-        assertEquals(/* expected= */ 4, metrics.length);
-    }
-
-    @Test
-    public void testGetTargetQualityMetrics_lowComplexityAlphanumeric() {
-        PasswordMetrics metrics = getTargetQualityMetrics(
-                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_ALPHANUMERIC);
-
-        assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, metrics.quality);
-        assertEquals(/* expected= */ 4, metrics.length);
-    }
-
-    @Test
-    public void testGetActualRequiredQuality_nonComplex() {
-        int actual = getActualRequiredQuality(
-                PASSWORD_QUALITY_NUMERIC_COMPLEX,
-                /* requiresNumeric= */ false,
-                /* requiresLettersOrSymbols= */ false);
-
-        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, actual);
-    }
-
-    @Test
-    public void testGetActualRequiredQuality_complexRequiresNone() {
-        int actual = getActualRequiredQuality(
-                PASSWORD_QUALITY_COMPLEX,
-                /* requiresNumeric= */ false,
-                /* requiresLettersOrSymbols= */ false);
-
-        assertEquals(PASSWORD_QUALITY_UNSPECIFIED, actual);
-    }
-
-    @Test
-    public void testGetActualRequiredQuality_complexRequiresNumeric() {
-        int actual = getActualRequiredQuality(
-                PASSWORD_QUALITY_COMPLEX,
-                /* requiresNumeric= */ true,
-                /* requiresLettersOrSymbols= */ false);
-
-        assertEquals(PASSWORD_QUALITY_NUMERIC, actual);
-    }
-
-    @Test
-    public void testGetActualRequiredQuality_complexRequiresLetters() {
-        int actual = getActualRequiredQuality(
-                PASSWORD_QUALITY_COMPLEX,
-                /* requiresNumeric= */ false,
-                /* requiresLettersOrSymbols= */ true);
-
-        assertEquals(PASSWORD_QUALITY_ALPHABETIC, actual);
-    }
-
-    @Test
-    public void testGetActualRequiredQuality_complexRequiresNumericAndLetters() {
-        int actual = getActualRequiredQuality(
-                PASSWORD_QUALITY_COMPLEX,
-                /* requiresNumeric= */ true,
-                /* requiresLettersOrSymbols= */ true);
-
-        assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, actual);
-    }
-
-    @Test
-    public void testGetMinimumMetrics_userInputStricter() {
-        PasswordMetrics metrics = getMinimumMetrics(
-                PASSWORD_COMPLEXITY_HIGH,
-                PASSWORD_QUALITY_ALPHANUMERIC,
-                PASSWORD_QUALITY_NUMERIC,
-                /* requiresNumeric= */ false,
-                /* requiresLettersOrSymbols= */ false);
-
-        assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, metrics.quality);
-        assertEquals(/* expected= */ 6, metrics.length);
-    }
-
-    @Test
-    public void testGetMinimumMetrics_actualRequiredQualityStricter() {
-        PasswordMetrics metrics = getMinimumMetrics(
-                PASSWORD_COMPLEXITY_HIGH,
-                PASSWORD_QUALITY_UNSPECIFIED,
-                PASSWORD_QUALITY_NUMERIC,
-                /* requiresNumeric= */ false,
-                /* requiresLettersOrSymbols= */ false);
-
-        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
-        assertEquals(/* expected= */ 8, metrics.length);
+        for (int i = 0; i < expected.length / 2; i++) {
+            final int expectedError = expected[i * 2];
+            final int expectedRequirement = expected[i * 2 + 1];
+            assertTrue("error expected but not reported: " + expectedError,
+                    errorMap.containsKey(expectedError));
+            assertEquals("unexpected requirement for error: " + expectedError,
+                    Integer.valueOf(expectedRequirement), errorMap.get(expectedError));
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java b/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
new file mode 100644
index 0000000..e951054
--- /dev/null
+++ b/core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.admin.PasswordMetrics;
+import android.app.admin.PasswordPolicy;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class PasswordPolicyTest {
+
+    public static final int TEST_VALUE = 10;
+
+    @Test
+    public void testGetMinMetrics_unspecified() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_UNSPECIFIED);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_NONE, minMetrics.credType);
+        assertEquals(0, minMetrics.length);
+        assertEquals(0, minMetrics.numeric);
+    }
+
+    @Test
+    public void testGetMinMetrics_something() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_SOMETHING);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PATTERN, minMetrics.credType);
+        assertEquals(0, minMetrics.length);
+        assertEquals(0, minMetrics.numeric);
+    }
+
+    @Test
+    public void testGetMinMetrics_biometricWeak() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_BIOMETRIC_WEAK);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PATTERN, minMetrics.credType);
+        assertEquals(0, minMetrics.length);
+        assertEquals(0, minMetrics.numeric);
+    }
+
+    @Test
+    public void testGetMinMetrics_numeric() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(TEST_VALUE, minMetrics.length);
+        assertEquals(0, minMetrics.numeric); // numeric can doesn't really require digits.
+        assertEquals(0, minMetrics.letters);
+        assertEquals(0, minMetrics.lowerCase);
+        assertEquals(0, minMetrics.upperCase);
+        assertEquals(0, minMetrics.symbols);
+        assertEquals(0, minMetrics.nonLetter);
+        assertEquals(0, minMetrics.nonNumeric);
+        assertEquals(Integer.MAX_VALUE, minMetrics.seqLength);
+    }
+
+    @Test
+    public void testGetMinMetrics_numericDefaultLength() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC);
+        policy.length = 0; // reset to default
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(0, minMetrics.length);
+    }
+
+    @Test
+    public void testGetMinMetrics_numericComplex() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(TEST_VALUE, minMetrics.length);
+        assertEquals(0, minMetrics.numeric);
+        assertEquals(0, minMetrics.letters);
+        assertEquals(0, minMetrics.lowerCase);
+        assertEquals(0, minMetrics.upperCase);
+        assertEquals(0, minMetrics.symbols);
+        assertEquals(0, minMetrics.nonLetter);
+        assertEquals(0, minMetrics.nonNumeric);
+        assertEquals(PasswordMetrics.MAX_ALLOWED_SEQUENCE, minMetrics.seqLength);
+    }
+
+    @Test
+    public void testGetMinMetrics_alphabetic() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_ALPHABETIC);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(TEST_VALUE, minMetrics.length);
+        assertEquals(0, minMetrics.numeric);
+        assertEquals(0, minMetrics.letters);
+        assertEquals(0, minMetrics.lowerCase);
+        assertEquals(0, minMetrics.upperCase);
+        assertEquals(0, minMetrics.symbols);
+        assertEquals(0, minMetrics.nonLetter);
+        assertEquals(1, minMetrics.nonNumeric);
+        assertEquals(Integer.MAX_VALUE, minMetrics.seqLength);
+    }
+
+    @Test
+    public void testGetMinMetrics_alphanumeric() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_ALPHANUMERIC);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(TEST_VALUE, minMetrics.length);
+        assertEquals(1, minMetrics.numeric);
+        assertEquals(0, minMetrics.letters);
+        assertEquals(0, minMetrics.lowerCase);
+        assertEquals(0, minMetrics.upperCase);
+        assertEquals(0, minMetrics.symbols);
+        assertEquals(0, minMetrics.nonLetter);
+        assertEquals(1, minMetrics.nonNumeric);
+        assertEquals(Integer.MAX_VALUE, minMetrics.seqLength);
+    }
+
+    @Test
+    public void testGetMinMetrics_complex() {
+        PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_COMPLEX);
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(TEST_VALUE, minMetrics.length);
+        assertEquals(TEST_VALUE, minMetrics.letters);
+        assertEquals(TEST_VALUE, minMetrics.lowerCase);
+        assertEquals(TEST_VALUE, minMetrics.upperCase);
+        assertEquals(TEST_VALUE, minMetrics.symbols);
+        assertEquals(TEST_VALUE, minMetrics.numeric);
+        assertEquals(TEST_VALUE, minMetrics.nonLetter);
+        assertEquals(0, minMetrics.nonNumeric);
+        assertEquals(Integer.MAX_VALUE, minMetrics.seqLength);
+    }
+
+    @Test
+    public void testGetMinMetrics_complexDefault() {
+        PasswordPolicy policy = new PasswordPolicy();
+        policy.quality = PASSWORD_QUALITY_COMPLEX;
+        PasswordMetrics minMetrics = policy.getMinMetrics();
+        assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType);
+        assertEquals(0, minMetrics.length);
+        assertEquals(1, minMetrics.letters);
+        assertEquals(0, minMetrics.lowerCase);
+        assertEquals(0, minMetrics.upperCase);
+        assertEquals(1, minMetrics.symbols);
+        assertEquals(1, minMetrics.numeric);
+        assertEquals(0, minMetrics.nonLetter);
+        assertEquals(0, minMetrics.nonNumeric);
+        assertEquals(Integer.MAX_VALUE, minMetrics.seqLength);
+    }
+
+    private PasswordPolicy testPolicy(int quality) {
+        PasswordPolicy result = new PasswordPolicy();
+        result.quality = quality;
+        result.length = TEST_VALUE;
+        result.letters = TEST_VALUE;
+        result.lowerCase = TEST_VALUE;
+        result.upperCase = TEST_VALUE;
+        result.numeric = TEST_VALUE;
+        result.symbols = TEST_VALUE;
+        result.nonLetter = TEST_VALUE;
+        return result;
+    }
+}
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index 987c3b4..7296cfd 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -29,6 +29,8 @@
          'service' attribute here is a flattened ComponentName string. -->
     <backup-transport-whitelisted-service
         service="com.android.localtransport/.LocalTransportService" />
+    <backup-transport-whitelisted-service
+        service="com.android.encryptedlocaltransport/.EncryptedLocalTransportService" />
 
     <!-- Whitelist Shell to use the bugreport API -->
     <bugreport-whitelisted package="com.android.shell" />
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 9c4b5e8..06d4fbd 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1380,9 +1380,9 @@
      */
     @NonNull
     static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) {
-        if (index < 0 || index >= Named.values().length) {
+        if (index < 0 || index >= sNamedColorSpaces.length) {
             throw new IllegalArgumentException("Invalid ID, must be in the range [0.." +
-                    Named.values().length + ")");
+                    sNamedColorSpaces.length + ")");
         }
         return sNamedColorSpaces[index];
     }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index bf23634..254456c 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -350,7 +350,7 @@
      * access manually.
      */
     public static final String KEY_ALIAS_SELECTION_DENIED =
-            "alias-selection-denied-ef829e15-210a-409d-96c9-ee684fc41972";
+            "android:alias-selection-denied";
 
     /**
      * Returns an {@code Intent} that can be used for credential
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 6824be8..27274d1 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -1211,7 +1211,8 @@
     }
 
     /**
-     * Attaches an extra {@link Location} to this Location.
+     * Attaches an extra {@link Location} to this Location. This is useful for location providers
+     * to set the {@link #EXTRA_NO_GPS_LOCATION} extra to provide coarse locations for clients.
      *
      * @param key the key associated with the Location extra
      * @param value the Location to attach
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 0b3e1c3..70bfb54 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1971,7 +1971,7 @@
     public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {}
 
     /**
-     * Registers a GPS Measurement callback.
+     * Registers a GPS Measurement callback which will run on a binder threadS.
      *
      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
@@ -1983,7 +1983,7 @@
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean registerGnssMeasurementsCallback(
             @NonNull GnssMeasurementsEvent.Callback callback) {
-        return registerGnssMeasurementsCallback(callback, null);
+        return registerGnssMeasurementsCallback(Runnable::run, callback);
     }
 
     /**
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 7ed431d..cc5ddeb 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -224,7 +224,7 @@
      * @return The meta data value associate with the given keyCode on success;
      * null on failure.
      */
-    public native String extractMetadata(int keyCode);
+    public native @Nullable String extractMetadata(int keyCode);
 
     /**
      * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)}
@@ -255,7 +255,7 @@
      *
      * @see {@link #getFrameAtTime(long, int, BitmapParams)}
      */
-    public Bitmap getFrameAtTime(long timeUs, @Option int option) {
+    public @Nullable Bitmap getFrameAtTime(long timeUs, @Option int option) {
         if (option < OPTION_PREVIOUS_SYNC ||
             option > OPTION_CLOSEST) {
             throw new IllegalArgumentException("Unsupported option: " + option);
@@ -301,7 +301,7 @@
      *
      * @see {@link #getFrameAtTime(long, int)}
      */
-    public Bitmap getFrameAtTime(
+    public @Nullable Bitmap getFrameAtTime(
             long timeUs, @Option int option, @NonNull BitmapParams params) {
         if (option < OPTION_PREVIOUS_SYNC ||
             option > OPTION_CLOSEST) {
@@ -343,7 +343,7 @@
      *         is less than or equal to 0.
      * @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
      */
-    public Bitmap getScaledFrameAtTime(
+    public @Nullable Bitmap getScaledFrameAtTime(
             long timeUs, @Option int option, int dstWidth, int dstHeight) {
         validate(option, dstWidth, dstHeight);
         return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
@@ -388,7 +388,7 @@
      *         is less than or equal to 0.
      * @see {@link #getScaledFrameAtTime(long, int, int, int)}
      */
-    public Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
+    public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
             int dstWidth, int dstHeight, @NonNull BitmapParams params) {
         validate(option, dstWidth, dstHeight);
         return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
@@ -430,7 +430,7 @@
      *
      * @see #getFrameAtTime(long, int)
      */
-    public Bitmap getFrameAtTime(long timeUs) {
+    public @Nullable Bitmap getFrameAtTime(long timeUs) {
         return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC);
     }
 
@@ -452,7 +452,7 @@
      * @see #getFrameAtTime(long)
      * @see #getFrameAtTime(long, int)
      */
-    public Bitmap getFrameAtTime() {
+    public @Nullable Bitmap getFrameAtTime() {
         return _getFrameAtTime(
                 -1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/, null);
     }
@@ -528,7 +528,7 @@
      * @see #getFramesAtIndex(int, int, BitmapParams)
      * @see #getFramesAtIndex(int, int)
      */
-    public Bitmap getFrameAtIndex(int frameIndex, @NonNull BitmapParams params) {
+    public @Nullable Bitmap getFrameAtIndex(int frameIndex, @NonNull BitmapParams params) {
         List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params);
         return bitmaps.get(0);
     }
@@ -550,7 +550,7 @@
      * @see #getFramesAtIndex(int, int, BitmapParams)
      * @see #getFramesAtIndex(int, int)
      */
-    public Bitmap getFrameAtIndex(int frameIndex) {
+    public @Nullable Bitmap getFrameAtIndex(int frameIndex) {
         List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1);
         return bitmaps.get(0);
     }
@@ -653,7 +653,7 @@
      * @see #getPrimaryImage(BitmapParams)
      * @see #getPrimaryImage()
      */
-    public Bitmap getImageAtIndex(int imageIndex, @NonNull BitmapParams params) {
+    public @Nullable Bitmap getImageAtIndex(int imageIndex, @NonNull BitmapParams params) {
         return getImageAtIndexInternal(imageIndex, params);
     }
 
@@ -691,7 +691,7 @@
      * @see #getPrimaryImage(BitmapParams)
      * @see #getPrimaryImage()
      */
-    public Bitmap getImageAtIndex(int imageIndex) {
+    public @Nullable Bitmap getImageAtIndex(int imageIndex) {
         return getImageAtIndexInternal(imageIndex, null);
     }
 
@@ -713,7 +713,7 @@
      * @see #getImageAtIndex(int)
      * @see #getPrimaryImage()
      */
-    public Bitmap getPrimaryImage(@NonNull BitmapParams params) {
+    public @Nullable Bitmap getPrimaryImage(@NonNull BitmapParams params) {
         return getImageAtIndexInternal(-1, params);
     }
 
@@ -729,7 +729,7 @@
      * @see #getImageAtIndex(int)
      * @see #getPrimaryImage(BitmapParams)
      */
-    public Bitmap getPrimaryImage() {
+    public @Nullable Bitmap getPrimaryImage() {
         return getImageAtIndexInternal(-1, null);
     }
 
@@ -755,7 +755,7 @@
      *
      * @return null if no such graphic is found.
      */
-    public byte[] getEmbeddedPicture() {
+    public @Nullable byte[] getEmbeddedPicture() {
         return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
     }
 
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index abd774d..b9fdde3 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -79,6 +79,8 @@
     @Nullable
     final Bundle mExtras;
 
+    private final String mUniqueId;
+
     MediaRoute2Info(@NonNull Builder builder) {
         mId = builder.mId;
         mProviderId = builder.mProviderId;
@@ -90,6 +92,7 @@
         mVolumeMax = builder.mVolumeMax;
         mVolumeHandling = builder.mVolumeHandling;
         mExtras = builder.mExtras;
+        mUniqueId = createUniqueId();
     }
 
     MediaRoute2Info(@NonNull Parcel in) {
@@ -103,6 +106,15 @@
         mVolumeMax = in.readInt();
         mVolumeHandling = in.readInt();
         mExtras = in.readBundle();
+        mUniqueId = createUniqueId();
+    }
+
+    private String createUniqueId() {
+        String uniqueId = null;
+        if (mProviderId != null) {
+            uniqueId = mProviderId + ":" + mId;
+        }
+        return uniqueId;
     }
 
     /**
@@ -147,13 +159,33 @@
         return Objects.hash(mId, mName, mDescription, mSupportedCategories);
     }
 
+    /**
+     * Gets the id of the route.
+     * Use {@link #getUniqueId()} if you need a unique identifier.
+     *
+     * @see #getUniqueId()
+     */
     @NonNull
     public String getId() {
         return mId;
     }
 
     /**
-     * Gets the provider id of the route.
+     * Gets the unique id of the route. A route obtained from
+     * {@link com.android.server.media.MediaRouterService} always has a unique id.
+     *
+     * @return unique id of the route or null if it has no unique id.
+     */
+    @Nullable
+    public String getUniqueId() {
+        return mUniqueId;
+    }
+
+    /**
+     * Gets the provider id of the route. It is assigned automatically by
+     * {@link com.android.server.media.MediaRouterService}.
+     *
+     * @return provider id of the route or null if it's not set.
      * @hide
      */
     @Nullable
diff --git a/packages/BackupEncryption/Android.bp b/packages/BackupEncryption/Android.bp
index 342d796..68e937c 100644
--- a/packages/BackupEncryption/Android.bp
+++ b/packages/BackupEncryption/Android.bp
@@ -17,8 +17,7 @@
 android_app {
     name: "BackupEncryption",
     srcs: ["src/**/*.java"],
-    libs: ["backup-encryption-protos"],
-    static_libs: ["backuplib"],
+    static_libs: ["backup-encryption-protos", "backuplib"],
     optimize: { enabled: false },
     platform_apis: true,
     certificate: "platform",
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/EncryptionKeyHelper.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/EncryptionKeyHelper.java
new file mode 100644
index 0000000..2035b66
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/EncryptionKeyHelper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.RecoveryController;
+
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+class EncryptionKeyHelper {
+    private static SecureRandom sSecureRandom = new  SecureRandom();
+
+    private final Context mContext;
+    private final RecoverableKeyStoreSecondaryKeyManager
+            .RecoverableKeyStoreSecondaryKeyManagerProvider
+            mSecondaryKeyManagerProvider;
+
+    EncryptionKeyHelper(Context context) {
+        mContext = context;
+        mSecondaryKeyManagerProvider =
+                () ->
+                        new RecoverableKeyStoreSecondaryKeyManager(
+                                RecoveryController.getInstance(mContext), sSecureRandom);
+    }
+
+    RecoverableKeyStoreSecondaryKeyManager
+            .RecoverableKeyStoreSecondaryKeyManagerProvider getKeyManagerProvider() {
+        return mSecondaryKeyManagerProvider;
+    }
+
+    RecoverableKeyStoreSecondaryKey getActiveSecondaryKey()
+            throws UnrecoverableKeyException, InternalRecoveryServiceException {
+        String keyAlias = CryptoSettings.getInstance(mContext).getActiveSecondaryKeyAlias().get();
+        return mSecondaryKeyManagerProvider.get().get(keyAlias).get();
+    }
+
+    SecretKey getTertiaryKey(
+            String packageName,
+            RecoverableKeyStoreSecondaryKey secondaryKey)
+            throws IllegalBlockSizeException, InvalidAlgorithmParameterException,
+            NoSuchAlgorithmException, IOException, NoSuchPaddingException,
+            InvalidKeyException {
+        TertiaryKeyManager tertiaryKeyManager =
+                new TertiaryKeyManager(
+                        mContext,
+                        sSecureRandom,
+                        TertiaryKeyRotationScheduler.getInstance(mContext),
+                        secondaryKey,
+                        packageName);
+        return tertiaryKeyManager.getKey();
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/KeyValueEncrypter.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/KeyValueEncrypter.java
new file mode 100644
index 0000000..1d841b4
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/KeyValueEncrypter.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import static com.android.server.backup.encryption.BackupEncryptionService.TAG;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.KeyWrapUtils;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+import com.android.server.backup.encryption.tasks.EncryptedKvBackupTask;
+import com.android.server.backup.encryption.tasks.EncryptedKvRestoreTask;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Map;
+
+public class KeyValueEncrypter {
+    private final Context mContext;
+    private final EncryptionKeyHelper mKeyHelper;
+
+    public KeyValueEncrypter(Context context) {
+        mContext = context;
+        mKeyHelper = new EncryptionKeyHelper(mContext);
+    }
+
+    public void encryptKeyValueData(
+            String packageName, ParcelFileDescriptor inputFd, OutputStream outputStream)
+            throws Exception {
+        EncryptedKvBackupTask.EncryptedKvBackupTaskFactory backupTaskFactory =
+                new EncryptedKvBackupTask.EncryptedKvBackupTaskFactory();
+        EncryptedKvBackupTask backupTask =
+                backupTaskFactory.newInstance(
+                        mContext,
+                        new SecureRandom(),
+                        new FileBackupServer(outputStream),
+                        CryptoSettings.getInstance(mContext),
+                        mKeyHelper.getKeyManagerProvider(),
+                        inputFd,
+                        packageName);
+        backupTask.performBackup(/* incremental */ false);
+    }
+
+    public void decryptKeyValueData(String packageName,
+            InputStream encryptedInputStream, ParcelFileDescriptor outputFd) throws Exception {
+        RecoverableKeyStoreSecondaryKey secondaryKey = mKeyHelper.getActiveSecondaryKey();
+
+        EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory restoreTaskFactory =
+                new EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory();
+        EncryptedKvRestoreTask restoreTask =
+                restoreTaskFactory.newInstance(
+                        mContext,
+                        mKeyHelper.getKeyManagerProvider(),
+                        new InputStreamFullRestoreDownloader(encryptedInputStream),
+                        secondaryKey.getAlias(),
+                        KeyWrapUtils.wrap(
+                                secondaryKey.getSecretKey(),
+                                mKeyHelper.getTertiaryKey(packageName, secondaryKey)));
+
+        restoreTask.getRestoreData(outputFd);
+    }
+
+    // TODO(b/142455725): Extract into a commong class.
+    private static class FileBackupServer implements CryptoBackupServer {
+        private static final String EMPTY_DOC_ID = "";
+
+        private final OutputStream mOutputStream;
+
+        FileBackupServer(OutputStream outputStream) {
+            mOutputStream = outputStream;
+        }
+
+        @Override
+        public String uploadIncrementalBackup(
+                String packageName,
+                String oldDocId,
+                byte[] diffScript,
+                WrappedKeyProto.WrappedKey tertiaryKey) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String uploadNonIncrementalBackup(
+                String packageName, byte[] data, WrappedKeyProto.WrappedKey tertiaryKey) {
+            try {
+                mOutputStream.write(data);
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to write encrypted data to file: ", e);
+            }
+
+            return EMPTY_DOC_ID;
+        }
+
+        @Override
+        public void setActiveSecondaryKeyAlias(
+                String keyAlias, Map<String, WrappedKeyProto.WrappedKey> tertiaryKeys) {
+            // Do nothing.
+        }
+    }
+
+    // TODO(b/142455725): Extract into a commong class.
+    private static class InputStreamFullRestoreDownloader extends FullRestoreDownloader {
+        private final InputStream mInputStream;
+
+        InputStreamFullRestoreDownloader(InputStream inputStream) {
+            mInputStream = inputStream;
+        }
+
+        @Override
+        public int readNextChunk(byte[] buffer) throws IOException {
+            return mInputStream.read(buffer);
+        }
+
+        @Override
+        public void finish(FinishType finishType) {
+            try {
+                mInputStream.close();
+            } catch (IOException e) {
+                Log.w(TAG, "Error while reading restore data");
+            }
+        }
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java
index 1d0224d..c3cb335 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java
@@ -18,27 +18,58 @@
 
 import static com.android.server.backup.encryption.BackupEncryptionService.TAG;
 
+import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.encryption.KeyValueEncrypter;
 import com.android.server.backup.transport.DelegatingTransport;
 import com.android.server.backup.transport.TransportClient;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.atomic.AtomicReference;
+
 /**
  * This is an implementation of {@link IBackupTransport} that encrypts (or decrypts) the data when
  * sending it (or receiving it) from the {@link IBackupTransport} returned by {@link
  * TransportClient.connect(String)}.
  */
 public class IntermediateEncryptingTransport extends DelegatingTransport {
+    private static final String BACKUP_TEMP_DIR = "backup";
+    private static final String RESTORE_TEMP_DIR = "restore";
+
     private final TransportClient mTransportClient;
     private final Object mConnectLock = new Object();
+    private final Context mContext;
     private volatile IBackupTransport mRealTransport;
+    private AtomicReference<String> mNextRestorePackage = new AtomicReference<>();
+    private final KeyValueEncrypter mKeyValueEncrypter;
+    private final boolean mShouldEncrypt;
+
+    IntermediateEncryptingTransport(
+            TransportClient transportClient, Context context, boolean shouldEncrypt) {
+        this(transportClient, context, new KeyValueEncrypter(context), shouldEncrypt);
+    }
 
     @VisibleForTesting
-    IntermediateEncryptingTransport(TransportClient transportClient) {
+    IntermediateEncryptingTransport(
+            TransportClient transportClient, Context context, KeyValueEncrypter keyValueEncrypter,
+            boolean shouldEncrypt) {
         mTransportClient = transportClient;
+        mContext = context;
+        mKeyValueEncrypter = keyValueEncrypter;
+        mShouldEncrypt = shouldEncrypt;
     }
 
     @Override
@@ -46,9 +77,116 @@
         if (mRealTransport == null) {
             connect();
         }
+        Log.d(TAG, "real transport = " + mRealTransport.name());
         return mRealTransport;
     }
 
+    @Override
+    public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
+            throws RemoteException {
+        if (!mShouldEncrypt) {
+            return super.performBackup(packageInfo, inFd, flags);
+        }
+
+        File encryptedStorageFile = getBackupTempStorage(packageInfo.packageName);
+        if (encryptedStorageFile == null) {
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        // Encrypt the backup data and write it into a temp file.
+        try (OutputStream encryptedOutput = new FileOutputStream(encryptedStorageFile)) {
+            mKeyValueEncrypter.encryptKeyValueData(packageInfo.packageName, inFd,
+                    encryptedOutput);
+        } catch (Throwable e) {
+            Log.e(TAG, "Failed to encrypt backup data: ", e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        // Pass the temp file to the real transport for backup.
+        try (FileInputStream encryptedInput = new FileInputStream(encryptedStorageFile)) {
+            return super.performBackup(
+                    packageInfo, ParcelFileDescriptor.dup(encryptedInput.getFD()), flags);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to read encrypted data from temp storage: ", e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+    }
+
+    @Override
+    public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
+        if (!mShouldEncrypt) {
+            return super.getRestoreData(outFd);
+        }
+
+        String nextRestorePackage = mNextRestorePackage.get();
+        if (nextRestorePackage == null) {
+            Log.e(TAG, "No next restore package set");
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        File encryptedStorageFile = getRestoreTempStorage(nextRestorePackage);
+        if (encryptedStorageFile == null) {
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        // Get encrypted restore data from the real transport and write it into a temp file.
+        try (FileOutputStream outputStream = new FileOutputStream(encryptedStorageFile)) {
+            int status = super.getRestoreData(ParcelFileDescriptor.dup(outputStream.getFD()));
+            if (status != BackupTransport.TRANSPORT_OK) {
+                Log.e(TAG, "Failed to read restore data from transport, status = " + status);
+                return status;
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to write encrypted data to temp storage: ", e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        // Decrypt the data and write it into the fd given by the real transport.
+        try (InputStream inputStream = new FileInputStream(encryptedStorageFile)) {
+            mKeyValueEncrypter.decryptKeyValueData(nextRestorePackage, inputStream, outFd);
+            encryptedStorageFile.delete();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to decrypt restored data: ", e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    @Override
+    public RestoreDescription nextRestorePackage() throws RemoteException {
+        if (!mShouldEncrypt) {
+            return super.nextRestorePackage();
+        }
+
+        RestoreDescription restoreDescription = super.nextRestorePackage();
+        mNextRestorePackage.set(restoreDescription.getPackageName());
+
+        return restoreDescription;
+    }
+
+    @VisibleForTesting
+    protected File getBackupTempStorage(String packageName) {
+        return getTempStorage(packageName, BACKUP_TEMP_DIR);
+    }
+
+    @VisibleForTesting
+    protected File getRestoreTempStorage(String packageName) {
+        return getTempStorage(packageName, RESTORE_TEMP_DIR);
+    }
+
+    private File getTempStorage(String packageName, String operationType) {
+        File encryptedDir = new File(mContext.getFilesDir(), operationType);
+        encryptedDir.mkdir();
+        File encryptedFile = new File(encryptedDir, packageName);
+        try {
+            encryptedFile.createNewFile();
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to create temp file for encrypted data: ", e);
+        }
+        return encryptedFile;
+    }
+
     private void connect() throws RemoteException {
         Log.i(TAG, "connecting " + mTransportClient);
         synchronized (mConnectLock) {
@@ -65,4 +203,9 @@
     TransportClient getClient() {
         return mTransportClient;
     }
+
+    @VisibleForTesting
+    void setNextRestorePackage(String nextRestorePackage) {
+        mNextRestorePackage.set(nextRestorePackage);
+    }
 }
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java
index 6e6d571..7c4082c 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java
@@ -26,20 +26,20 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.server.backup.transport.TransportClientManager;
 import com.android.server.backup.transport.TransportStats;
 
 import java.util.HashMap;
 import java.util.Map;
 
-/**
- * Handles creation and cleanup of {@link IntermediateEncryptingTransport} instances.
- */
+/** Handles creation and cleanup of {@link IntermediateEncryptingTransport} instances. */
 public class IntermediateEncryptingTransportManager {
     private static final String CALLER = "IntermediateEncryptingTransportManager";
     private final TransportClientManager mTransportClientManager;
     private final Object mTransportsLock = new Object();
     private final Map<ComponentName, IntermediateEncryptingTransport> mTransports = new HashMap<>();
+    private Context mContext;
 
     @VisibleForTesting
     IntermediateEncryptingTransportManager(TransportClientManager transportClientManager) {
@@ -48,6 +48,7 @@
 
     public IntermediateEncryptingTransportManager(Context context) {
         this(new TransportClientManager(UserHandle.myUserId(), context, new TransportStats()));
+        mContext = context;
     }
 
     /**
@@ -55,31 +56,42 @@
      * provide a {@link IntermediateEncryptingTransport} which is an implementation of {@link
      * IBackupTransport} that encrypts (or decrypts) the data when sending it (or receiving it) from
      * the real {@link IBackupTransport}.
+     *
      * @param intent {@link Intent} created with a call to {@link
-     * TransportClientManager.getEncryptingTransportIntent(ComponentName)}.
+     *     TransportClientManager.getEncryptingTransportIntent(ComponentName)}.
      * @return
      */
     public IntermediateEncryptingTransport get(Intent intent) {
         Intent transportIntent = TransportClientManager.getRealTransportIntent(intent);
         Log.i(TAG, "get: intent:" + intent + " transportIntent:" + transportIntent);
         synchronized (mTransportsLock) {
-            return mTransports.computeIfAbsent(transportIntent.getComponent(),
-                    c -> create(transportIntent));
+            return mTransports.computeIfAbsent(
+                    transportIntent.getComponent(), c -> create(transportIntent));
         }
     }
 
-    /**
-     * Create an instance of {@link IntermediateEncryptingTransport}.
-     */
+    /** Create an instance of {@link IntermediateEncryptingTransport}. */
     private IntermediateEncryptingTransport create(Intent realTransportIntent) {
         Log.d(TAG, "create: intent:" + realTransportIntent);
-        return new IntermediateEncryptingTransport(mTransportClientManager.getTransportClient(
-                realTransportIntent.getComponent(), realTransportIntent.getExtras(), CALLER));
+
+        LockPatternUtils patternUtils = new LockPatternUtils(mContext);
+        boolean shouldEncrypt =
+                realTransportIntent.getComponent().getClassName().contains("EncryptedLocalTransport")
+                        && (patternUtils.isLockPatternEnabled(UserHandle.myUserId())
+                                || patternUtils.isLockPasswordEnabled(UserHandle.myUserId()));
+
+        return new IntermediateEncryptingTransport(
+                mTransportClientManager.getTransportClient(
+                        realTransportIntent.getComponent(),
+                        realTransportIntent.getExtras(),
+                        CALLER),
+                mContext,
+                shouldEncrypt);
     }
 
     /**
-     * Cleanup the {@link IntermediateEncryptingTransport} which was created by a call to
-     * {@link #get(Intent)} with this {@link Intent}.
+     * Cleanup the {@link IntermediateEncryptingTransport} which was created by a call to {@link
+     * #get(Intent)} with this {@link Intent}.
      */
     public void cleanup(Intent intent) {
         Intent transportIntent = TransportClientManager.getRealTransportIntent(intent);
diff --git a/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java b/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java
index cc4b0ab..a85b2e4 100644
--- a/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java
+++ b/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java
@@ -18,43 +18,71 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.backup.BackupTransport;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.encryption.KeyValueEncrypter;
 import com.android.server.backup.transport.TransportClient;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.File;
+
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class IntermediateEncryptingTransportTest {
-    @Mock private IBackupTransport mRealTransport;
-    @Mock private TransportClient mTransportClient;
+    private static final String TEST_PACKAGE_NAME = "test_package";
 
     private IntermediateEncryptingTransport mIntermediateEncryptingTransport;
+    private final PackageInfo mTestPackage = new PackageInfo();
+
+    @Mock private IBackupTransport mRealTransport;
+    @Mock private TransportClient mTransportClient;
+    @Mock private ParcelFileDescriptor mParcelFileDescriptor;
+    @Mock private KeyValueEncrypter mKeyValueEncrypter;
+    @Mock private Context mContext;
+
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+    private File mTempFile;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mIntermediateEncryptingTransport = new IntermediateEncryptingTransport(mTransportClient);
+
+        mIntermediateEncryptingTransport =
+                new IntermediateEncryptingTransport(
+                        mTransportClient, mContext, mKeyValueEncrypter, true);
+        mTestPackage.packageName = TEST_PACKAGE_NAME;
+        mTempFile = mTemporaryFolder.newFile();
+
+        when(mTransportClient.connect(anyString())).thenReturn(mRealTransport);
+        when(mRealTransport.getRestoreData(any())).thenReturn(BackupTransport.TRANSPORT_OK);
     }
 
     @Test
     public void testGetDelegate_callsConnect() throws Exception {
-        when(mTransportClient.connect(anyString())).thenReturn(mRealTransport);
-
         IBackupTransport ret = mIntermediateEncryptingTransport.getDelegate();
 
         assertEquals(mRealTransport, ret);
@@ -74,4 +102,79 @@
         verify(mTransportClient, times(1)).connect(anyString());
         verifyNoMoreInteractions(mTransportClient);
     }
+
+    @Test
+    public void testPerformBackup_shouldEncryptTrue_encryptsDataAndPassesToDelegate()
+            throws Exception {
+        mIntermediateEncryptingTransport =
+                new TestIntermediateTransport(mTransportClient, mContext, mKeyValueEncrypter, true);
+
+        mIntermediateEncryptingTransport.performBackup(mTestPackage, mParcelFileDescriptor, 0);
+
+        verify(mKeyValueEncrypter, times(1))
+                .encryptKeyValueData(eq(TEST_PACKAGE_NAME), eq(mParcelFileDescriptor), any());
+        verify(mRealTransport, times(1)).performBackup(eq(mTestPackage), any(), eq(0));
+    }
+
+    @Test
+    public void testPerformBackup_shouldEncryptFalse_doesntEncryptDataAndPassedToDelegate()
+            throws Exception {
+        mIntermediateEncryptingTransport =
+                new TestIntermediateTransport(
+                        mTransportClient, mContext, mKeyValueEncrypter, false);
+
+        mIntermediateEncryptingTransport.performBackup(mTestPackage, mParcelFileDescriptor, 0);
+
+        verifyZeroInteractions(mKeyValueEncrypter);
+        verify(mRealTransport, times(1))
+                .performBackup(eq(mTestPackage), eq(mParcelFileDescriptor), eq(0));
+    }
+
+    @Test
+    public void testGetRestoreData_shouldEncryptTrue_decryptsDataAndPassesToDelegate()
+            throws Exception {
+        mIntermediateEncryptingTransport =
+                new TestIntermediateTransport(mTransportClient, mContext, mKeyValueEncrypter, true);
+        mIntermediateEncryptingTransport.setNextRestorePackage(TEST_PACKAGE_NAME);
+
+        mIntermediateEncryptingTransport.getRestoreData(mParcelFileDescriptor);
+
+        verify(mKeyValueEncrypter, times(1))
+                .decryptKeyValueData(eq(TEST_PACKAGE_NAME), any(), eq(mParcelFileDescriptor));
+        verify(mRealTransport, times(1)).getRestoreData(any());
+    }
+
+    @Test
+    public void testGetRestoreData_shouldEncryptFalse_doesntDecryptDataAndPassesToDelegate()
+            throws Exception {
+        mIntermediateEncryptingTransport =
+                new TestIntermediateTransport(
+                        mTransportClient, mContext, mKeyValueEncrypter, false);
+        mIntermediateEncryptingTransport.setNextRestorePackage(TEST_PACKAGE_NAME);
+
+        mIntermediateEncryptingTransport.getRestoreData(mParcelFileDescriptor);
+
+        verifyZeroInteractions(mKeyValueEncrypter);
+        verify(mRealTransport, times(1)).getRestoreData(eq(mParcelFileDescriptor));
+    }
+
+    private final class TestIntermediateTransport extends IntermediateEncryptingTransport {
+        TestIntermediateTransport(
+                TransportClient transportClient,
+                Context context,
+                KeyValueEncrypter keyValueEncrypter,
+                boolean shouldEncrypt) {
+            super(transportClient, context, keyValueEncrypter, shouldEncrypt);
+        }
+
+        @Override
+        protected File getBackupTempStorage(String packageName) {
+            return mTempFile;
+        }
+
+        @Override
+        protected File getRestoreTempStorage(String packageName) {
+            return mTempFile;
+        }
+    }
 }
diff --git a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
index 72ec8d8..94f5b96 100644
--- a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
@@ -48,6 +48,18 @@
         />
 
         <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/grid"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            systemui:intent="intent:#Intent;component=com.android.car.home/.AppGridActivity;end"
+            systemui:longIntent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
+            android:src="@drawable/car_ic_apps"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingTop="30dp"
+            android:paddingBottom="30dp"
+        />
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
             android:id="@+id/hvac"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
@@ -58,6 +70,7 @@
             android:paddingTop="30dp"
             android:paddingBottom="30dp"
         />
+
     </LinearLayout>
 
     <LinearLayout
@@ -78,6 +91,7 @@
             android:alpha="0.7"
         />
 
+
         <com.android.systemui.statusbar.policy.Clock
             android:id="@+id/clock"
             android:textAppearance="@style/TextAppearance.StatusBar.Clock"
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 897976f..18ae582 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -22,6 +22,8 @@
     android:layout_height="match_parent"
     android:background="@drawable/system_bar_background"
     android:orientation="vertical">
+    <!--The 20dp padding is the difference between the background selected icon size and the ripple
+        that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
     <LinearLayout
         android:id="@id/nav_buttons"
         android:layout_width="match_parent"
@@ -37,7 +39,6 @@
             systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
             systemui:icon="@drawable/car_ic_overview"
             systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
-            systemui:longIntent="intent:#Intent;action=com.google.android.demandspace.START;end"
             systemui:selectedIcon="@drawable/car_ic_overview_selected"
             systemui:useMoreIcon="false"
         />
@@ -108,13 +109,11 @@
             android:layout_height="match_parent"
             android:layout_weight="1"/>
 
-        <!-- Click handling will be initialized in CarNavigationBarView because its
-             id = notifications which is treated special for the opening of the notification panel
-         -->
         <com.android.systemui.statusbar.car.CarNavigationButton
             android:id="@+id/notifications"
             style="@style/NavigationBarButton"
-            android:src="@drawable/car_ic_notification"
+            systemui:icon="@drawable/car_ic_notification"
+            systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"
             systemui:selectedIcon="@drawable/car_ic_notification_selected"
             systemui:useMoreIcon="false"
         />
@@ -124,13 +123,13 @@
             android:layout_height="match_parent"
             android:layout_weight="1"/>
 
-        <com.android.systemui.statusbar.car.CarFacetButton
+        <com.android.systemui.statusbar.car.AssitantButton
             android:id="@+id/assist"
             style="@style/NavigationBarButton"
             systemui:icon="@drawable/ic_mic_white"
-            systemui:intent="intent:#Intent;action=com.google.android.demandspace.START;end"
             systemui:useMoreIcon="false"
         />
+
     </LinearLayout>
 
     <LinearLayout
@@ -138,10 +137,11 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:paddingStart="@*android:dimen/car_keyline_1"
-        android:paddingEnd="@*android:dimen/car_keyline_1"
+        android:paddingStart="@dimen/car_keyline_1"
+        android:paddingEnd="@dimen/car_keyline_1"
         android:gravity="center"
         android:visibility="gone">
+
     </LinearLayout>
 
-</com.android.systemui.statusbar.car.CarNavigationBarView>
+</com.android.systemui.statusbar.car.CarNavigationBarView>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
index 72ec8d8..d36d1d6 100644
--- a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
@@ -25,6 +25,9 @@
     android:orientation="vertical"
     android:background="@drawable/system_bar_background">
 
+    <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
+         rotation so skip this level of the hierarchy.
+    -->
     <LinearLayout
         android:layout_height="match_parent"
         android:layout_width="match_parent"
@@ -48,6 +51,18 @@
         />
 
         <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/grid"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            systemui:intent="intent:#Intent;component=com.android.car.home/.AppGridActivity;launchFlags=0x14000000;end"
+            systemui:longIntent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
+            android:src="@drawable/car_ic_apps"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingTop="30dp"
+            android:paddingBottom="30dp"
+        />
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
             android:id="@+id/hvac"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
@@ -58,6 +73,7 @@
             android:paddingTop="30dp"
             android:paddingBottom="30dp"
         />
+
     </LinearLayout>
 
     <LinearLayout
@@ -78,6 +94,7 @@
             android:alpha="0.7"
         />
 
+
         <com.android.systemui.statusbar.policy.Clock
             android:id="@+id/clock"
             android:textAppearance="@style/TextAppearance.StatusBar.Clock"
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 9d47cdc..90aba2f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -113,6 +113,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -304,7 +305,8 @@
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
             StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild,
-            NotifLog notifLog) {
+            NotifLog notifLog,
+            DozeParameters dozeParameters) {
         super(
                 context,
                 lightBarController,
@@ -360,7 +362,8 @@
                 configurationController,
                 statusBarWindowController,
                 statusBarWindowViewControllerBuild,
-                notifLog);
+                notifLog,
+                dozeParameters);
         mNavigationBarController = navigationBarController;
     }
 
diff --git a/packages/EncryptedLocalTransport/Android.bp b/packages/EncryptedLocalTransport/Android.bp
new file mode 100644
index 0000000..dd30ad1
--- /dev/null
+++ b/packages/EncryptedLocalTransport/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2019 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.
+//
+
+android_app {
+    name: "EncryptedLocalTransport",
+    srcs: ["src/**/*.java"],
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+    },
+    static_libs: ["LocalTransport"],
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+}
diff --git a/packages/EncryptedLocalTransport/AndroidManifest.xml b/packages/EncryptedLocalTransport/AndroidManifest.xml
new file mode 100644
index 0000000..dc3617f
--- /dev/null
+++ b/packages/EncryptedLocalTransport/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2019 Google Inc.
+ *
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.android.encryptedlocaltransport"
+      android:sharedUserId="android.uid.system" >
+
+
+    <application android:allowBackup="false" >
+        <!-- This service does not need to be exported because it shares uid with the system server
+        which is the only client. -->
+        <service android:name=".EncryptedLocalTransportService"
+                 android:permission="android.permission.CONFIRM_FULL_BACKUP"
+                 android:exported="false">
+            <intent-filter>
+                <action android:name="android.backup.TRANSPORT_HOST" />
+            </intent-filter>
+        </service>
+
+    </application>
+</manifest>
diff --git a/packages/EncryptedLocalTransport/proguard.flags b/packages/EncryptedLocalTransport/proguard.flags
new file mode 100644
index 0000000..e4ce3c5
--- /dev/null
+++ b/packages/EncryptedLocalTransport/proguard.flags
@@ -0,0 +1,2 @@
+-keep class com.android.localTransport.EncryptedLocalTransport
+-keep class com.android.localTransport.EncryptedLocalTransportService
diff --git a/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransport.java b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransport.java
new file mode 100644
index 0000000..3dd453e
--- /dev/null
+++ b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransport.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 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.encryptedlocaltransport;
+
+import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
+import android.util.Log;
+
+import com.android.localtransport.LocalTransport;
+import com.android.localtransport.LocalTransportParameters;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+
+public class EncryptedLocalTransport extends LocalTransport {
+    private static final String TAG = "EncryptedLocalTransport";
+    private static final int BACKUP_BUFFER_SIZE = 32 * 1024; // 32 KB.
+
+    public EncryptedLocalTransport(Context context,
+            LocalTransportParameters parameters) {
+        super(context, parameters);
+    }
+
+    @Override
+    public int performBackup(
+            PackageInfo packageInfo, ParcelFileDescriptor data, int flags) {
+        File packageFile;
+        try {
+            StructStat stat = Os.fstat(data.getFileDescriptor());
+            if (stat.st_size > KEY_VALUE_BACKUP_SIZE_QUOTA) {
+                Log.w(TAG, "New datastore size " + stat.st_size
+                        + " exceeds quota " + KEY_VALUE_BACKUP_SIZE_QUOTA);
+                return TRANSPORT_QUOTA_EXCEEDED;
+            }
+        } catch (ErrnoException e) {
+            Log.w(TAG, "Failed to stat the backup input file: ", e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        clearBackupData(packageInfo);
+
+        try (InputStream in = new FileInputStream(data.getFileDescriptor())) {
+            packageFile = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
+            Files.copy(in, packageFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to save backup data to file: ", e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        return TRANSPORT_OK;
+    }
+
+    @Override
+    public int getRestoreData(ParcelFileDescriptor outFd) {
+        if (mRestorePackages == null) {
+            throw new IllegalStateException("startRestore not called");
+        }
+        if (mRestorePackage < 0) {
+            throw new IllegalStateException("nextRestorePackage not called");
+        }
+        if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) {
+            throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset");
+        }
+
+        try(OutputStream out = new FileOutputStream(outFd.getFileDescriptor())) {
+            File packageFile = new File(mRestoreSetIncrementalDir,
+                    mRestorePackages[mRestorePackage].packageName);
+            Files.copy(packageFile.toPath(), out);
+        } catch (IOException e) {
+            Log.d(TAG, "Failed to transfer restore data: " + e);
+            return BackupTransport.TRANSPORT_ERROR;
+        }
+
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    @Override
+    protected boolean hasRestoreDataForPackage(String packageName) {
+        File contents = (new File(mRestoreSetIncrementalDir, packageName));
+        return contents.exists() && contents.length() != 0;
+
+    }
+}
diff --git a/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransportService.java b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransportService.java
new file mode 100644
index 0000000..952f90d
--- /dev/null
+++ b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransportService.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 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.encryptedlocaltransport;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.localtransport.LocalTransportParameters;
+
+public class EncryptedLocalTransportService extends Service {
+    private static EncryptedLocalTransport sTransport = null;
+
+    @Override
+    public void onCreate() {
+        if (sTransport == null) {
+            LocalTransportParameters parameters =
+                    new LocalTransportParameters(getMainThreadHandler(), getContentResolver());
+            sTransport = new EncryptedLocalTransport(this, parameters);
+        }
+        sTransport.getParameters().start();
+    }
+
+    @Override
+    public void onDestroy() {
+        sTransport.getParameters().stop();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sTransport.getBinder();
+    }
+}
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 4408ef5..50f858e 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -16,6 +16,7 @@
 
 package com.android.localtransport;
 
+import android.annotation.Nullable;
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
@@ -71,19 +72,19 @@
 
     // Size quotas at reasonable values, similar to the current cloud-storage limits
     private static final long FULL_BACKUP_SIZE_QUOTA = 25 * 1024 * 1024;
-    private static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
+    protected static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
 
     private Context mContext;
     private File mDataDir;
     private File mCurrentSetDir;
-    private File mCurrentSetIncrementalDir;
+    protected File mCurrentSetIncrementalDir;
     private File mCurrentSetFullDir;
 
-    private PackageInfo[] mRestorePackages = null;
-    private int mRestorePackage = -1;  // Index into mRestorePackages
-    private int mRestoreType;
+    protected PackageInfo[] mRestorePackages = null;
+    protected int mRestorePackage = -1;  // Index into mRestorePackages
+    protected int mRestoreType;
     private File mRestoreSetDir;
-    private File mRestoreSetIncrementalDir;
+    protected File mRestoreSetIncrementalDir;
     private File mRestoreSetFullDir;
 
     // Additional bookkeeping for full backup
@@ -115,7 +116,7 @@
         makeDataDirs();
     }
 
-    LocalTransportParameters getParameters() {
+    public LocalTransportParameters getParameters() {
         return mParameters;
     }
 
@@ -142,11 +143,18 @@
         return null;
     }
 
+    /** @removed Replaced with dataManagementIntentLabel in the API */
     public String dataManagementLabel() {
         return TRANSPORT_DATA_MANAGEMENT_LABEL;
     }
 
     @Override
+    @Nullable
+    public CharSequence dataManagementIntentLabel() {
+        return TRANSPORT_DATA_MANAGEMENT_LABEL;
+    }
+
+    @Override
     public String transportDirName() {
         return TRANSPORT_DIR_NAME;
     }
@@ -537,14 +545,14 @@
         int bytesLeft = numBytes;
         while (bytesLeft > 0) {
             try {
-            int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
-            if (nRead < 0) {
-                // Something went wrong if we expect data but saw EOD
-                Log.w(TAG, "Unexpected EOD; failing backup");
-                return TRANSPORT_ERROR;
-            }
-            mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
-            bytesLeft -= nRead;
+                int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
+                if (nRead < 0) {
+                    // Something went wrong if we expect data but saw EOD
+                    Log.w(TAG, "Unexpected EOD; failing backup");
+                    return TRANSPORT_ERROR;
+                }
+                mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
+                bytesLeft -= nRead;
             } catch (IOException e) {
                 Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
                 return TRANSPORT_ERROR;
@@ -620,20 +628,15 @@
         }
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
 
-        boolean found = false;
+        boolean found;
         while (++mRestorePackage < mRestorePackages.length) {
             String name = mRestorePackages[mRestorePackage].packageName;
 
             // If we have key/value data for this package, deliver that
             // skip packages where we have a data dir but no actual contents
-            String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
-            if (contents != null && contents.length > 0) {
-                if (DEBUG) {
-                    Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) @ "
-                        + mRestorePackage + " = " + name);
-                }
+            found = hasRestoreDataForPackage(name);
+            if (found) {
                 mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
-                found = true;
             }
 
             if (!found) {
@@ -664,6 +667,18 @@
         return RestoreDescription.NO_MORE_PACKAGES;
     }
 
+    protected boolean hasRestoreDataForPackage(String packageName) {
+        String[] contents = (new File(mRestoreSetIncrementalDir, packageName)).list();
+        if (contents != null && contents.length > 0) {
+            if (DEBUG) {
+                Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) @ "
+                        + mRestorePackage + " = " + packageName);
+            }
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public int getRestoreData(ParcelFileDescriptor outFd) {
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 784be22..8b4db92 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -22,7 +22,7 @@
 import android.provider.Settings;
 import android.util.KeyValueListParser;
 
-class LocalTransportParameters extends KeyValueSettingObserver {
+public class LocalTransportParameters extends KeyValueSettingObserver {
     private static final String TAG = "LocalTransportParams";
     private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
     private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
@@ -31,7 +31,7 @@
     private boolean mFakeEncryptionFlag;
     private boolean mIsNonIncrementalOnly;
 
-    LocalTransportParameters(Handler handler, ContentResolver resolver) {
+    public LocalTransportParameters(Handler handler, ContentResolver resolver) {
         super(handler, resolver, Settings.Secure.getUriFor(SETTING));
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index a18600a..2b84196 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -48,11 +48,21 @@
         return getEnabledServicesFromSettings(context, UserHandle.myUserId());
     }
 
+    /**
+     * Check if the accessibility service is crashed
+     *
+     * @param packageName The package name to check
+     * @param serviceName The service name to check
+     * @param installedServiceInfos The list of installed accessibility service
+     * @return {@code true} if the accessibility service is crashed for the user.
+     * {@code false} otherwise.
+     */
     public static boolean hasServiceCrashed(String packageName, String serviceName,
-            List<AccessibilityServiceInfo> enabledServiceInfos) {
-        for (int i = 0; i < enabledServiceInfos.size(); i++) {
-            AccessibilityServiceInfo accessibilityServiceInfo = enabledServiceInfos.get(i);
-            final ServiceInfo serviceInfo = enabledServiceInfos.get(i).getResolveInfo().serviceInfo;
+            List<AccessibilityServiceInfo> installedServiceInfos) {
+        for (int i = 0; i < installedServiceInfos.size(); i++) {
+            final AccessibilityServiceInfo accessibilityServiceInfo = installedServiceInfos.get(i);
+            final ServiceInfo serviceInfo =
+                    installedServiceInfos.get(i).getResolveInfo().serviceInfo;
             if (TextUtils.equals(serviceInfo.packageName, packageName)
                     && TextUtils.equals(serviceInfo.name, serviceName)) {
                 return accessibilityServiceInfo.crashed;
diff --git a/packages/SettingsProvider/src/android/provider/settings/OWNERS b/packages/SettingsProvider/src/android/provider/settings/OWNERS
index fad9ffc..541dd878 100644
--- a/packages/SettingsProvider/src/android/provider/settings/OWNERS
+++ b/packages/SettingsProvider/src/android/provider/settings/OWNERS
@@ -1,2 +1,5 @@
 # Please reach out to Android B&R when making Settings backup changes
-br-framework-team+reviews@google.com
+alsutton@google.com
+nathch@google.com
+rthakohov@google.com
+
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
new file mode 100644
index 0000000..e425790
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.settings.backup;
+
+import android.provider.Settings;
+
+/** Device specific settings list */
+public class DeviceSpecificSettings {
+    /**
+     * The settings values which should only be restored if the target device is the
+     * same as the source device
+     *
+     * NOTE: Settings are backed up and restored in the order they appear
+     *       in this array. If you have one setting depending on another,
+     *       make sure that they are ordered appropriately.
+     *
+     * @hide
+     */
+    public static final String[] DEVICE_SPECIFIC_SETTINGS_TO_BACKUP = {
+            Settings.Secure.DISPLAY_DENSITY_FORCED,
+    };
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 976f336..ef67bbd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -41,8 +41,8 @@
 public class SecureSettingsValidators {
     /**
      * All settings in {@link Secure.SETTINGS_TO_BACKUP} and {@link
-     * Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} array *must* have a non-null validator, otherwise
-     * they won't be restored.
+     * DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} array *must* have a non-null
+     * validator, otherwise they won't be restored.
      */
     public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index f545fa6..7e60452 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -34,6 +34,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.settings.backup.DeviceSpecificSettings;
 import android.provider.settings.backup.GlobalSettings;
 import android.provider.settings.backup.SecureSettings;
 import android.provider.settings.backup.SystemSettings;
@@ -641,7 +642,7 @@
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
             whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
                     Settings.Secure.LEGACY_RESTORE_SETTINGS,
-                    Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+                    DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
             validators = SecureSettingsValidators.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
             whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
@@ -1000,7 +1001,7 @@
                      getContentResolver()
                              .query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null)) {
             return extractRelevantValues(
-                    cursor, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+                    cursor, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
         }
     }
 
diff --git a/packages/SettingsProvider/test/src/android/provider/OWNERS b/packages/SettingsProvider/test/src/android/provider/OWNERS
index a3b4e40..f3241ea 100644
--- a/packages/SettingsProvider/test/src/android/provider/OWNERS
+++ b/packages/SettingsProvider/test/src/android/provider/OWNERS
@@ -1,4 +1,4 @@
 per-file * = *
 
 # Please reach out to the Android B&R team for settings backup changes
-per-file SettingsBackupTest.java = br-framework-team+reviews@google.com
+per-file SettingsBackupTest.java = alsutton@google.com, nathch@google.com, rthakohov@google.com
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 8437eae..62827bc 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -16,6 +16,8 @@
 
 package android.provider;
 
+import static android.provider.settings.backup.DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP;
+
 import static com.google.android.collect.Sets.newHashSet;
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -750,7 +752,7 @@
     public void secureSettingsBackedUpOrBlacklisted() {
         HashSet<String> keys = new HashSet<String>();
         Collections.addAll(keys, SecureSettings.SETTINGS_TO_BACKUP);
-        Collections.addAll(keys, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+        Collections.addAll(keys, DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
         checkSettingsBackedUpOrBlacklisted(
                 getCandidateSettings(Settings.Secure.class),
                 keys,
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 83acfa0..656827a 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -46,3 +46,6 @@
 #Android Auto
 stenning@google.com
 
+#Android TV
+rgl@google.com
+
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java
index cac673f..c1d4b03 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java
@@ -33,4 +33,9 @@
       * will add home controls to this space.
       */
     void sendParentGroup(ViewGroup group);
+
+    /**
+     * When visible, will poll for updates.
+     */
+    void setVisible(boolean visible);
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index db026ca..6518924 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -186,6 +186,8 @@
             return toStringBuilder().toString();
         }
 
+        // Used in dumps to determine current state of a tile.
+        // This string may be used for CTS testing of tiles, so removing elements is discouraged.
         protected StringBuilder toStringBuilder() {
             final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
             sb.append(",icon=").append(icon);
diff --git a/packages/SystemUI/res/drawable/ic_lightbulb_outline_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lightbulb_outline_gm2_24px.xml
new file mode 100644
index 0000000..87684a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lightbulb_outline_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M9,21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1L9,20v1zM12,2C8.14,2 5,5.14 5,9c0,2.38 1.19,4.47 3,5.74L8,17c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-2.26c1.81,-1.27 3,-3.36 3,-5.74 0,-3.86 -3.14,-7 -7,-7zM14.85,13.1l-0.85,0.6L14,16h-4v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,1.63 -0.8,3.16 -2.15,4.1z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/home_controls.xml b/packages/SystemUI/res/layout/home_controls.xml
new file mode 100644
index 0000000..bb971c2
--- /dev/null
+++ b/packages/SystemUI/res/layout/home_controls.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/home_controls_layout"
+    android:layout_width="match_parent"
+    android:layout_height="125dp"
+    android:layout_gravity="@integer/notification_panel_layout_gravity"
+    android:visibility="gone"
+    android:padding="8dp"
+    android:layout_margin="5dp"
+    android:background="?android:attr/colorBackgroundFloating"
+    android:orientation="vertical">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0e59a41..4869be1 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -51,17 +51,7 @@
             systemui:viewType="com.android.systemui.plugins.qs.QS" />
 
         <!-- Temporary area to test out home controls -->
-        <LinearLayout
-            android:id="@+id/home_controls_layout"
-            android:layout_width="match_parent"
-            android:layout_height="125dp"
-            android:layout_gravity="@integer/notification_panel_layout_gravity"
-            android:visibility="gone"
-            android:padding="8dp"
-            android:layout_margin="5dp"
-            android:background="?android:attr/colorBackgroundFloating"
-            android:orientation="vertical">
-        </LinearLayout>
+        <include layout="@layout/home_controls" />
 
         <com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
@@ -107,4 +97,4 @@
         android:background="@drawable/qs_navbar_scrim" />
 
     <include layout="@layout/status_bar_expanded_plugin_frame"/>
-</merge>
\ No newline at end of file
+</merge>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 105b27e..efcc2c4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -117,7 +117,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,controls
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8335c11..3cc683a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -129,6 +129,9 @@
     <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
     <string name="usb_device_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_device">%2$s</xliff:g>?</string>
 
+    <!-- Prompt for the USB device confirm dialog with warning text for USB device dialogs.  [CHAR LIMIT=200] -->
+    <string name="usb_device_confirm_prompt_warn">Open <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to handle <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device.</string>
+
     <!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
     <string name="usb_accessory_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_accessory">%2$s</xliff:g>?</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 07bfa71..ff8a932 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -17,6 +17,7 @@
 import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.INotificationManager;
+import android.app.IWallpaperManager;
 import android.content.res.Configuration;
 import android.hardware.SensorPrivacyManager;
 import android.hardware.display.NightDisplayListener;
@@ -77,6 +78,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
@@ -318,6 +320,8 @@
     @Inject Lazy<SysUiState> mSysUiStateFlagsContainer;
     @Inject Lazy<AlarmManager> mAlarmManager;
     @Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel;
+    @Inject Lazy<DozeParameters> mDozeParameters;
+    @Inject Lazy<IWallpaperManager> mWallpaperManager;
 
     @Inject
     public Dependency() {
@@ -504,6 +508,8 @@
         mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get);
         mProviders.put(AlarmManager.class, mAlarmManager::get);
         mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get);
+        mProviders.put(DozeParameters.class, mDozeParameters::get);
+        mProviders.put(IWallpaperManager.class, mWallpaperManager::get);
 
         // TODO(b/118592525): to support multi-display , we start to add something which is
         //                    per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index cf199c5..9192eed 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -22,26 +22,36 @@
 import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.AlarmManager;
+import android.app.IActivityManager;
 import android.app.INotificationManager;
+import android.app.IWallpaperManager;
 import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.SensorPrivacyManager;
+import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.view.IWindowManager;
+import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
@@ -59,7 +69,11 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.util.leak.LeakDetector;
 
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
 import javax.inject.Named;
+import javax.inject.Qualifier;
 import javax.inject.Singleton;
 
 import dagger.Module;
@@ -71,6 +85,12 @@
  */
 @Module
 public class DependencyProvider {
+    @Qualifier
+    @Documented
+    @Retention(RUNTIME)
+    public @interface MainResources {
+        // TODO: use attribute to get other, non-main resources?
+    }
 
     @Singleton
     @Provides
@@ -249,4 +269,48 @@
     public LockPatternUtils provideLockPatternUtils(Context context) {
         return new LockPatternUtils(context);
     }
+
+    /** */
+    @Provides
+    public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
+        return new AmbientDisplayConfiguration(context);
+    }
+
+    /** */
+    @Provides
+    public AlwaysOnDisplayPolicy provideAlwaysOnDisplayPolicy(Context context) {
+        return new AlwaysOnDisplayPolicy(context);
+    }
+
+    /** */
+    @Provides
+    public PowerManager providePowerManager(Context context) {
+        return context.getSystemService(PowerManager.class);
+    }
+
+    /** */
+    @Provides
+    @MainResources
+    public Resources provideResources(Context context) {
+        return context.getResources();
+    }
+
+    /** */
+    @Provides
+    public IWallpaperManager provideWallPaperManager() {
+        return IWallpaperManager.Stub.asInterface(
+                ServiceManager.getService(Context.WALLPAPER_SERVICE));
+    }
+
+    /** */
+    @Provides
+    public WindowManager providesWindowManager(Context context) {
+        return context.getSystemService(WindowManager.class);
+    }
+
+    /** */
+    @Provides
+    public IActivityManager providesIActivityManager() {
+        return ActivityManager.getService();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 1c0e0b3..29a7167 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -38,6 +38,8 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import javax.inject.Inject;
+
 /**
  * Default built-in wallpaper that simply shows a static image.
  */
@@ -50,8 +52,15 @@
     private static final int INTERVAL_WAIT_FOR_RENDERING = 100;
     private static final int PATIENCE_WAIT_FOR_RENDERING = 10;
     private static final boolean DEBUG = true;
+    private final DozeParameters mDozeParameters;
     private HandlerThread mWorker;
 
+    @Inject
+    public ImageWallpaper(DozeParameters dozeParameters) {
+        super();
+        mDozeParameters = dozeParameters;
+    }
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -61,7 +70,7 @@
 
     @Override
     public Engine onCreateEngine() {
-        return new GLEngine(this);
+        return new GLEngine(this, mDozeParameters);
     }
 
     @Override
@@ -89,9 +98,9 @@
         // This variable can only be accessed in synchronized block.
         private boolean mWaitingForRendering;
 
-        GLEngine(Context context) {
+        GLEngine(Context context, DozeParameters dozeParameters) {
             mNeedTransition = ActivityManager.isHighEndGfx()
-                    && !DozeParameters.getInstance(context).getDisplayNeedsBlanking();
+                    && !dozeParameters.getDisplayNeedsBlanking();
 
             // We will preserve EGL context when we are in lock screen or aod
             // to avoid janking in following transition, we need to release when back to home.
@@ -339,9 +348,9 @@
             boolean isHighEndGfx = ActivityManager.isHighEndGfx();
             out.print(prefix); out.print("isHighEndGfx="); out.println(isHighEndGfx);
 
-            DozeParameters dozeParameters = DozeParameters.getInstance(getApplicationContext());
             out.print(prefix); out.print("displayNeedsBlanking=");
-            out.println(dozeParameters != null ? dozeParameters.getDisplayNeedsBlanking() : "null");
+            out.println(
+                    mDozeParameters != null ? mDozeParameters.getDisplayNeedsBlanking() : "null");
 
             out.print(prefix); out.print("mNeedTransition="); out.println(mNeedTransition);
             out.print(prefix); out.print("StatusBarState=");
diff --git a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
index e61268e..c11236e 100644
--- a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
@@ -40,6 +40,12 @@
     /** */
     @Binds
     @IntoMap
+    @ClassKey(ImageWallpaper.class)
+    public abstract Service bindImageWallpaper(ImageWallpaper service);
+
+    /** */
+    @Binds
+    @IntoMap
     @ClassKey(KeyguardService.class)
     public abstract Service bindKeyguardService(KeyguardService service);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 189e511..91776a3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -237,7 +237,7 @@
                                 if (statusBar != null) {
                                     plugin.setup(statusBar.getStatusBarWindow(),
                                             statusBar.getNavigationBarView(), new Callback(plugin),
-                                            DozeParameters.getInstance(getBaseContext()));
+                                            Dependency.get(DozeParameters.class));
                                 }
                             }
                         });
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index da4f304..ef7526b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -160,7 +160,8 @@
             StatusBarStateController statusBarStateController) {
         return new NotificationIconAreaController(context, statusBar, statusBarStateController,
                 wakeUpCoordinator, keyguardBypassController,
-                Dependency.get(NotificationMediaManager.class));
+                Dependency.get(NotificationMediaManager.class),
+                Dependency.get(DozeParameters.class));
     }
 
     public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index 9958124..4cb1708 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -164,8 +164,11 @@
     }
 
     private void updateAssistHandleVisibility() {
-        AssistHandleViewController controller = Dependency.get(NavigationBarController.class)
-                .getAssistHandlerViewController();
+        NavigationBarController navigationBarController =
+                Dependency.get(NavigationBarController.class);
+        AssistHandleViewController controller =
+                navigationBarController == null
+                        ? null : navigationBarController.getAssistHandlerViewController();
         if (controller != null) {
             controller.setAssistHintBlocked(mInvocationInProgress);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
index 85a4d23..b726c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
+import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+
 import android.view.MotionEvent;
 
 import java.util.Locale;
@@ -29,6 +32,7 @@
 class PointerCountClassifier extends FalsingClassifier {
 
     private static final int MAX_ALLOWED_POINTERS = 1;
+    private static final int MAX_ALLOWED_POINTERS_SWIPE_DOWN = 2;
     private int mMaxPointerCount;
 
     PointerCountClassifier(FalsingDataProvider dataProvider) {
@@ -50,6 +54,10 @@
 
     @Override
     public boolean isFalseTouch() {
+        int interactionType = getInteractionType();
+        if (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN) {
+            return mMaxPointerCount > MAX_ALLOWED_POINTERS_SWIPE_DOWN;
+        }
         return mMaxPointerCount > MAX_ALLOWED_POINTERS;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index b069ba3..3f0505f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -18,6 +18,7 @@
 
 import android.app.AlarmManager;
 import android.app.Application;
+import android.app.IWallpaperManager;
 import android.content.Context;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
@@ -25,7 +26,6 @@
 import android.os.Handler;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.dock.DockManager;
@@ -39,47 +39,71 @@
 import com.android.systemui.util.wakelock.DelayedWakeLock;
 import com.android.systemui.util.wakelock.WakeLock;
 
+import javax.inject.Inject;
+
 public class DozeFactory {
 
-    public DozeFactory() {
+    private final FalsingManager mFalsingManager;
+    private final DozeLog mDozeLog;
+    private final DozeParameters mDozeParameters;
+    private final BatteryController mBatteryController;
+    private final AsyncSensorManager mAsyncSensorManager;
+    private final AlarmManager mAlarmManager;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final DockManager mDockManager;
+    private final IWallpaperManager mWallpaperManager;
+
+    @Inject
+    public DozeFactory(FalsingManager falsingManager, DozeLog dozeLog,
+            DozeParameters dozeParameters, BatteryController batteryController,
+            AsyncSensorManager asyncSensorManager, AlarmManager alarmManager,
+            WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DockManager dockManager, IWallpaperManager wallpaperManager) {
+        mFalsingManager = falsingManager;
+        mDozeLog = dozeLog;
+        mDozeParameters = dozeParameters;
+        mBatteryController = batteryController;
+        mAsyncSensorManager = asyncSensorManager;
+        mAlarmManager = alarmManager;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mDockManager = dockManager;
+        mWallpaperManager = wallpaperManager;
     }
 
     /** Creates a DozeMachine with its parts for {@code dozeService}. */
-    public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager,
-            DozeLog dozeLog) {
-        Context context = dozeService;
-        AsyncSensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
-        AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
-        DockManager dockManager = Dependency.get(DockManager.class);
-        WakefulnessLifecycle wakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
-
+    public DozeMachine assembleMachine(DozeService dozeService) {
         DozeHost host = getHost(dozeService);
-        AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
-        DozeParameters params = DozeParameters.getInstance(context);
+        AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(dozeService);
         Handler handler = new Handler();
         WakeLock wakeLock = new DelayedWakeLock(handler,
-                WakeLock.createPartial(context, "Doze"));
+                WakeLock.createPartial(dozeService, "Doze"));
 
         DozeMachine.Service wrappedService = dozeService;
         wrappedService = new DozeBrightnessHostForwarder(wrappedService, host);
-        wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(wrappedService, params);
-        wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(wrappedService,
-                params);
+        wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
+                wrappedService, mDozeParameters);
+        wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+                wrappedService, mDozeParameters);
 
         DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
-                wakefulnessLifecycle, Dependency.get(BatteryController.class), dozeLog);
+                                              mWakefulnessLifecycle, mBatteryController, mDozeLog);
         machine.setParts(new DozeMachine.Part[]{
-                new DozePauser(handler, machine, alarmManager, params.getPolicy()),
-                new DozeFalsingManagerAdapter(falsingManager),
-                createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
-                        handler, wakeLock, machine, dockManager, dozeLog),
-                createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params,
-                        dozeLog),
-                new DozeScreenState(wrappedService, handler, host, params, wakeLock),
-                createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
-                        handler),
-                new DozeWallpaperState(context, getBiometricUnlockController(dozeService)),
-                new DozeDockHandler(context, machine, host, config, handler, dockManager),
+                new DozePauser(handler, machine, mAlarmManager, mDozeParameters.getPolicy()),
+                new DozeFalsingManagerAdapter(mFalsingManager),
+                createDozeTriggers(dozeService, mAsyncSensorManager, host, mAlarmManager, config,
+                        mDozeParameters, handler, wakeLock, machine, mDockManager, mDozeLog),
+                createDozeUi(dozeService, host, wakeLock, machine, handler, mAlarmManager,
+                        mDozeParameters, mDozeLog),
+                new DozeScreenState(wrappedService, handler, host, mDozeParameters, wakeLock),
+                createDozeScreenBrightness(dozeService, wrappedService, mAsyncSensorManager, host,
+                        mDozeParameters, handler),
+                new DozeWallpaperState(
+                        mWallpaperManager,
+                        getBiometricUnlockController(dozeService),
+                        mDozeParameters),
+                new DozeDockHandler(dozeService, machine, host, config, handler, mDockManager),
                 new DozeAuthRemover(dozeService)
         });
 
@@ -110,7 +134,7 @@
             DozeMachine machine, Handler handler, AlarmManager alarmManager,
             DozeParameters params, DozeLog dozeLog) {
         return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params,
-                Dependency.get(KeyguardUpdateMonitor.class), dozeLog);
+                          mKeyguardUpdateMonitor, dozeLog);
     }
 
     public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 17559c9..08734d2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -22,10 +22,8 @@
 import android.service.dreams.DreamService;
 import android.util.Log;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.plugins.DozeServicePlugin;
 import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.shared.plugins.PluginManager;
 
@@ -38,18 +36,17 @@
         implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
     private static final String TAG = "DozeService";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private final FalsingManager mFalsingManager;
-    private final DozeLog mDozeLog;
+    private final DozeFactory mDozeFactory;
 
     private DozeMachine mDozeMachine;
     private DozeServicePlugin mDozePlugin;
     private PluginManager mPluginManager;
 
     @Inject
-    public DozeService(FalsingManager falsingManager, DozeLog dozeLog) {
+    public DozeService(DozeFactory dozeFactory, PluginManager pluginManager) {
         setDebug(DEBUG);
-        mFalsingManager = falsingManager;
-        mDozeLog = dozeLog;
+        mDozeFactory = dozeFactory;
+        mPluginManager = pluginManager;
     }
 
     @Override
@@ -62,9 +59,8 @@
             finish();
             return;
         }
-        mPluginManager = Dependency.get(PluginManager.class);
         mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
-        mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager, mDozeLog);
+        mDozeMachine = mDozeFactory.assembleMachine(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 35c8b74..9457dc9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -17,12 +17,9 @@
 package com.android.systemui.doze;
 
 import android.app.IWallpaperManager;
-import android.content.Context;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
@@ -42,17 +39,10 @@
     private final BiometricUnlockController mBiometricUnlockController;
     private boolean mIsAmbientMode;
 
-    public DozeWallpaperState(Context context,
-            BiometricUnlockController biometricUnlockController) {
-        this(IWallpaperManager.Stub.asInterface(
-                ServiceManager.getService(Context.WALLPAPER_SERVICE)),
-                biometricUnlockController,
-                DozeParameters.getInstance(context));
-    }
-
-    @VisibleForTesting
-    DozeWallpaperState(IWallpaperManager wallpaperManagerService,
-            BiometricUnlockController biometricUnlockController, DozeParameters parameters) {
+    public DozeWallpaperState(
+            IWallpaperManager wallpaperManagerService,
+            BiometricUnlockController biometricUnlockController,
+            DozeParameters parameters) {
         mWallpaperManagerService = wallpaperManagerService;
         mBiometricUnlockController = biometricUnlockController;
         mDozeParameters = parameters;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index a9fe54b..4d061e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -49,6 +49,12 @@
     private static final String TAG = "WorkLockActivity";
 
     /**
+     * Add additional extra {@link com.android.settings.password.ConfirmDeviceCredentialActivity} to
+     * enable device policy management enforcement from systemui.
+     */
+    public static final String EXTRA_FROM_WORK_LOCK_ACTIVITY = "from_work_lock_activity";
+
+    /**
      * Contains a {@link TaskDescription} for the activity being covered.
      */
     static final String EXTRA_TASK_DESCRIPTION =
@@ -151,6 +157,7 @@
 
         if (target != null) {
             credential.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
+            credential.putExtra(EXTRA_FROM_WORK_LOCK_ACTIVITY, true);
         }
 
         startActivityForResult(credential, REQUEST_CODE_CONFIRM_CREDENTIALS);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 466c808..411980b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -39,6 +39,7 @@
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
+import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
@@ -82,6 +83,11 @@
         mTile = new Tile();
         updateDefaultTileAndIcon();
         mServiceManager = host.getTileServices().getTileWrapper(this);
+        if (mServiceManager.isBooleanTile()) {
+            // Replace states with BooleanState
+            resetStates();
+        }
+
         mService = mServiceManager.getTileService();
         mServiceManager.setTileChangeListener(this);
         mUser = ActivityManager.getCurrentUser();
@@ -246,8 +252,10 @@
 
     @Override
     public State newTileState() {
-        State state = new State();
-        return state;
+        if (mServiceManager != null && mServiceManager.isBooleanTile()) {
+            return new BooleanState();
+        }
+        return new State();
     }
 
     @Override
@@ -336,6 +344,12 @@
         } else {
             state.contentDescription = state.label;
         }
+
+        if (state instanceof BooleanState) {
+            state.expandedAccessibilityClassName = Switch.class.getName();
+            ((BooleanState) state).value = (state.state == Tile.STATE_ACTIVE);
+        }
+
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index effea6a..f59e0c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -131,6 +131,24 @@
     }
 
     /**
+     * Determines whether the associated TileService is a Boolean Tile.
+     *
+     * @return true if {@link TileService#META_DATA_BOOLEAN_TILE} is set to {@code true} for this
+     *         tile
+     * @see TileService#META_DATA_BOOLEAN_TILE
+     */
+    public boolean isBooleanTile() {
+        try {
+            ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
+            return info.metaData != null
+                    && info.metaData.getBoolean(TileService.META_DATA_BOOLEAN_TILE, false);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    /**
      * Binds just long enough to send any queued messages, then unbinds.
      */
     public void flushMessagesAndUnbind() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 2a7e55f..0b4e648 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -123,6 +123,10 @@
         return mStateManager.isActiveTile();
     }
 
+    public boolean isBooleanTile() {
+        return mStateManager.isBooleanTile();
+    }
+
     public void setShowingDialog(boolean dialog) {
         mShowingDialog = dialog;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index daaee4c..1c8e451 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -16,6 +16,7 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 
@@ -32,6 +33,7 @@
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
+import com.android.systemui.qs.tiles.ControlsTile;
 import com.android.systemui.qs.tiles.DataSaverTile;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.FlashlightTile;
@@ -58,6 +60,7 @@
 
     private final Provider<WifiTile> mWifiTileProvider;
     private final Provider<BluetoothTile> mBluetoothTileProvider;
+    private final Provider<ControlsTile> mControlsTileProvider;
     private final Provider<CellularTile> mCellularTileProvider;
     private final Provider<DndTile> mDndTileProvider;
     private final Provider<ColorInversionTile> mColorInversionTileProvider;
@@ -81,6 +84,7 @@
     @Inject
     public QSFactoryImpl(Provider<WifiTile> wifiTileProvider,
             Provider<BluetoothTile> bluetoothTileProvider,
+            Provider<ControlsTile> controlsTileProvider,
             Provider<CellularTile> cellularTileProvider,
             Provider<DndTile> dndTileProvider,
             Provider<ColorInversionTile> colorInversionTileProvider,
@@ -100,6 +104,7 @@
             Provider<UiModeNightTile> uiModeNightTileProvider) {
         mWifiTileProvider = wifiTileProvider;
         mBluetoothTileProvider = bluetoothTileProvider;
+        mControlsTileProvider = controlsTileProvider;
         mCellularTileProvider = cellularTileProvider;
         mDndTileProvider = dndTileProvider;
         mColorInversionTileProvider = colorInversionTileProvider;
@@ -138,6 +143,11 @@
                 return mWifiTileProvider.get();
             case "bt":
                 return mBluetoothTileProvider.get();
+            case "controls":
+                if (Settings.System.getInt(mHost.getContext().getContentResolver(),
+                        "qs_controls_tile_enabled", 0) == 1) {
+                    return mControlsTileProvider.get();
+                } else return null;
             case "cell":
                 return mCellularTileProvider.get();
             case "dnd":
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 681de37..e0f26cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -139,6 +139,11 @@
         mQSSettingsPanelOption = QSSettingsControllerKt.getQSSettingsPanelOption();
     }
 
+    protected final void resetStates() {
+        mState = newTileState();
+        mTmpState = newTileState();
+    }
+
     @NonNull
     @Override
     public Lifecycle getLifecycle() {
@@ -629,6 +634,11 @@
         }
     }
 
+    /**
+     * Dumps the state of this tile along with its name.
+     *
+     * This may be used for CTS testing of tiles.
+     */
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(this.getClass().getSimpleName() + ":");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
new file mode 100644
index 0000000..0a59618
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.HomeControlsPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.qs.DetailAdapter;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.shared.plugins.PluginManager;
+
+import javax.inject.Inject;
+
+
+/**
+ * Temporary control test for prototyping
+ */
+public class ControlsTile extends QSTileImpl<BooleanState> {
+    private ControlsDetailAdapter mDetailAdapter;
+    private final ActivityStarter mActivityStarter;
+    private PluginManager mPluginManager;
+    private HomeControlsPlugin mPlugin;
+    private Intent mHomeAppIntent;
+
+    @Inject
+    public ControlsTile(QSHost host,
+            ActivityStarter activityStarter,
+            PluginManager pluginManager) {
+        super(host);
+        mActivityStarter = activityStarter;
+        mPluginManager = pluginManager;
+        mDetailAdapter = (ControlsDetailAdapter) createDetailAdapter();
+
+        mHomeAppIntent = new Intent(Intent.ACTION_VIEW);
+        mHomeAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mHomeAppIntent.setComponent(new ComponentName("com.google.android.apps.chromecast.app",
+                "com.google.android.apps.chromecast.app.DiscoveryActivity"));
+    }
+
+    @Override
+    public DetailAdapter getDetailAdapter() {
+        return mDetailAdapter;
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {
+
+    }
+
+    @Override
+    public void setDetailListening(boolean listening) {
+        if (mPlugin == null) return;
+
+        mPlugin.setVisible(listening);
+    }
+
+    @Override
+    protected void handleClick() {
+        showDetail(true);
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return mHomeAppIntent;
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        showDetail(true);
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return "Controls";
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        state.icon = ResourceIcon.get(R.drawable.ic_lightbulb_outline_gm2_24px);
+        state.label = "Controls";
+    }
+
+    @Override
+    public boolean supportsDetailView() {
+        return getDetailAdapter() != null && mQSSettingsPanelOption == QSSettingsPanel.OPEN_CLICK;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return -1;
+    }
+
+    @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return "On";
+        } else {
+            return "Off";
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    protected DetailAdapter createDetailAdapter() {
+        mDetailAdapter = new ControlsDetailAdapter();
+        return mDetailAdapter;
+    }
+
+    private class ControlsDetailAdapter implements DetailAdapter {
+        private View mDetailView;
+        protected LinearLayout mHomeControlsLayout;
+
+        public CharSequence getTitle() {
+            return "Controls";
+        }
+
+        public Boolean getToggleState() {
+            return null;
+        }
+
+        public boolean getToggleEnabled() {
+            return false;
+        }
+
+        public View createDetailView(Context context, View convertView, final ViewGroup parent) {
+            mHomeControlsLayout = (LinearLayout) LayoutInflater.from(context).inflate(
+                R.layout.home_controls, parent, false);
+            mHomeControlsLayout.setVisibility(View.VISIBLE);
+            mPluginManager.addPluginListener(
+                    new PluginListener<HomeControlsPlugin>() {
+                        @Override
+                        public void onPluginConnected(HomeControlsPlugin plugin,
+                                                      Context pluginContext) {
+                            mPlugin = plugin;
+                            mPlugin.sendParentGroup(mHomeControlsLayout);
+                            mPlugin.setVisible(true);
+                        }
+
+                        @Override
+                        public void onPluginDisconnected(HomeControlsPlugin plugin) {
+
+                        }
+                    }, HomeControlsPlugin.class, false);
+            return mHomeControlsLayout;
+        }
+
+        public Intent getSettingsIntent() {
+            return mHomeAppIntent;
+        }
+
+        public void setToggleState(boolean state) {
+
+        }
+
+        public int getMetricsCategory() {
+            return -1;
+        }
+
+        public boolean hasHeader() {
+            return false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 2f67f90..8a23e37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -37,10 +37,10 @@
 
 @Singleton
 class NotificationWakeUpCoordinator @Inject constructor(
-        private val mContext: Context,
         private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
         private val statusBarStateController: StatusBarStateController,
-        private val bypassController: KeyguardBypassController)
+        private val bypassController: KeyguardBypassController,
+        private val dozeParameters: DozeParameters)
     : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
         PanelExpansionListener {
 
@@ -67,7 +67,6 @@
     private var mVisibilityAmount = 0.0f
     private var mLinearVisibilityAmount = 0.0f
     private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
-    private val mDozeParameters: DozeParameters
     private var pulseExpanding: Boolean = false
     private val wakeUpListeners = arrayListOf<WakeUpListener>()
     private var state: Int = StatusBarState.KEYGUARD
@@ -146,7 +145,6 @@
     init {
         mHeadsUpManagerPhone.addListener(this)
         statusBarStateController.addCallback(this)
-        mDozeParameters = DozeParameters.getInstance(mContext)
         addListener(object : WakeUpListener {
             override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
                 if (isFullyHidden && mNotificationsVisibleForExpansion) {
@@ -377,7 +375,7 @@
     }
 
     private fun shouldAnimateVisibility() =
-            mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking()
+            dozeParameters.getAlwaysOn() && !dozeParameters.getDisplayNeedsBlanking()
 
     interface WakeUpListener {
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 7cbdfb0..548afd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -128,6 +128,7 @@
     private final KeyguardBypassController mKeyguardBypassController;
     private PowerManager.WakeLock mWakeLock;
     private final KeyguardUpdateMonitor mUpdateMonitor;
+    private final DozeParameters mDozeParameters;
     private final KeyguardStateController mKeyguardStateController;
     private final StatusBarWindowController mStatusBarWindowController;
     private final Context mContext;
@@ -146,31 +147,33 @@
 
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
-    public BiometricUnlockController(Context context,
+    public BiometricUnlockController(
+            Context context,
             DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator,
             ScrimController scrimController,
             StatusBar statusBar,
             KeyguardStateController keyguardStateController, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            KeyguardBypassController keyguardBypassController) {
+            KeyguardBypassController keyguardBypassController,
+            DozeParameters dozeParameters) {
         this(context, dozeScrimController, keyguardViewMediator, scrimController, statusBar,
                 keyguardStateController, handler, keyguardUpdateMonitor,
                 context.getResources()
                         .getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze),
-                keyguardBypassController);
+                keyguardBypassController, dozeParameters);
     }
 
     @VisibleForTesting
-    protected BiometricUnlockController(Context context,
-            DozeScrimController dozeScrimController, KeyguardViewMediator keyguardViewMediator,
-            ScrimController scrimController, StatusBar statusBar,
-            KeyguardStateController keyguardStateController, Handler handler,
+    protected BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
+            KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
+            StatusBar statusBar, KeyguardStateController keyguardStateController, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor, int wakeUpDelay,
-            KeyguardBypassController keyguardBypassController) {
+            KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters) {
         mContext = context;
         mPowerManager = context.getSystemService(PowerManager.class);
         mUpdateMonitor = keyguardUpdateMonitor;
+        mDozeParameters = dozeParameters;
         mUpdateMonitor.registerCallback(this);
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
@@ -284,7 +287,7 @@
         }
         // During wake and unlock, we need to draw black before waking up to avoid abrupt
         // brightness changes due to display state transitions.
-        boolean alwaysOnEnabled = DozeParameters.getInstance(mContext).getAlwaysOn();
+        boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
         boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
         Runnable wakeUp = ()-> {
             if (!wasDeviceInteractive) {
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 bb6a38e..28dac87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.PowerManager;
 import android.os.SystemProperties;
@@ -25,7 +25,7 @@
 import android.util.MathUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
+import com.android.systemui.DependencyProvider;
 import com.android.systemui.R;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.doze.DozeScreenState;
@@ -33,9 +33,13 @@
 
 import java.io.PrintWriter;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Retrieve doze information
  */
+@Singleton
 public class DozeParameters implements TunerService.Tunable,
         com.android.systemui.plugins.statusbar.DozeParameters {
     private static final int MAX_DURATION = 60 * 1000;
@@ -44,35 +48,33 @@
     public static final boolean FORCE_BLANKING =
             SystemProperties.getBoolean("debug.force_blanking", false);
 
-    private static DozeParameters sInstance;
-
-    private final Context mContext;
     private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     private final PowerManager mPowerManager;
 
     private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
+    private final Resources mResources;
 
     private boolean mDozeAlwaysOn;
     private boolean mControlScreenOffAnimation;
 
-    public static DozeParameters getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new DozeParameters(context);
-        }
-        return sInstance;
-    }
-
-    @VisibleForTesting
-    protected DozeParameters(Context context) {
-        mContext = context.getApplicationContext();
-        mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
-        mAlwaysOnPolicy = new AlwaysOnDisplayPolicy(mContext);
+    @Inject
+    protected DozeParameters(
+            @DependencyProvider.MainResources Resources resources,
+            AmbientDisplayConfiguration ambientDisplayConfiguration,
+            AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
+            PowerManager powerManager,
+            TunerService tunerService) {
+        mResources = resources;
+        mAmbientDisplayConfiguration = ambientDisplayConfiguration;
+        mAlwaysOnPolicy = alwaysOnDisplayPolicy;
 
         mControlScreenOffAnimation = !getDisplayNeedsBlanking();
-        mPowerManager = mContext.getSystemService(PowerManager.class);
+        mPowerManager = powerManager;
         mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
 
-        Dependency.get(TunerService.class).addTunable(this, Settings.Secure.DOZE_ALWAYS_ON,
+        tunerService.addTunable(
+                this,
+                Settings.Secure.DOZE_ALWAYS_ON,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
     }
 
@@ -95,7 +97,7 @@
     }
 
     public boolean getDozeSuspendDisplayStateSupported() {
-        return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported);
+        return mResources.getBoolean(R.bool.doze_suspend_display_state_supported);
     }
 
     public int getPulseDuration() {
@@ -103,7 +105,7 @@
     }
 
     public float getScreenBrightnessDoze() {
-        return mContext.getResources().getInteger(
+        return mResources.getInteger(
                 com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
     }
 
@@ -173,7 +175,7 @@
      * @return {@code true} if screen needs to be completely black before a power transition.
      */
     public boolean getDisplayNeedsBlanking() {
-        return FORCE_BLANKING || !FORCE_NO_BLANKING && mContext.getResources().getBoolean(
+        return FORCE_BLANKING || !FORCE_NO_BLANKING && mResources.getBoolean(
                 com.android.internal.R.bool.config_displayBlanksAfterDoze);
     }
 
@@ -195,24 +197,20 @@
     }
 
     private boolean getBoolean(String propName, int resId) {
-        return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
+        return SystemProperties.getBoolean(propName, mResources.getBoolean(resId));
     }
 
     private int getInt(String propName, int resId) {
-        int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId));
+        int value = SystemProperties.getInt(propName, mResources.getInteger(resId));
         return MathUtils.constrain(value, 0, MAX_DURATION);
     }
 
-    private String getString(String propName, int resId) {
-        return SystemProperties.get(propName, mContext.getString(resId));
-    }
-
     public int getPulseVisibleDurationExtended() {
         return 2 * getPulseVisibleDuration();
     }
 
     public boolean doubleTapReportsTouchCoordinates() {
-        return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
+        return mResources.getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9804f9f..ae18833 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1212,8 +1212,11 @@
         setClipChildren(shouldClip);
         setClipToPadding(shouldClip);
 
-        AssistHandleViewController controller = Dependency.get(NavigationBarController.class)
-                .getAssistHandlerViewController();
+        NavigationBarController navigationBarController =
+                Dependency.get(NavigationBarController.class);
+        AssistHandleViewController controller =
+                navigationBarController == null
+                        ? null : navigationBarController.getAssistHandlerViewController();
         if (controller != null) {
             controller.setBottomOffset(insets.getSystemWindowInsetBottom());
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 1a3560e..1a37520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -80,11 +80,14 @@
     private boolean mAodIconsVisible;
     private boolean mIsPulsing;
 
-    public NotificationIconAreaController(Context context, StatusBar statusBar,
+    public NotificationIconAreaController(
+            Context context,
+            StatusBar statusBar,
             StatusBarStateController statusBarStateController,
             NotificationWakeUpCoordinator wakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
-            NotificationMediaManager notificationMediaManager) {
+            NotificationMediaManager notificationMediaManager,
+            DozeParameters dozeParameters) {
         mStatusBar = statusBar;
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
         mContext = context;
@@ -92,7 +95,7 @@
         mStatusBarStateController = statusBarStateController;
         mStatusBarStateController.addCallback(this);
         mMediaManager = notificationMediaManager;
-        mDozeParameters = DozeParameters.getInstance(mContext);
+        mDozeParameters = dozeParameters;
         mWakeUpCoordinator = wakeUpCoordinator;
         wakeUpCoordinator.addListener(this);
         mBypassController = keyguardBypassController;
@@ -533,8 +536,7 @@
     }
 
     public void appearAodIcons() {
-        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
-        if (dozeParameters.shouldControlScreenOff()) {
+        if (mDozeParameters.shouldControlScreenOff()) {
             mAodIcons.setTranslationY(-mAodIconAppearTranslation);
             mAodIcons.setAlpha(0);
             animateInAodIconTranslation();
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 9ab635c..89051cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -146,6 +146,7 @@
      * Fling until QS is completely hidden.
      */
     public static final int FLING_HIDE = 2;
+    private final DozeParameters mDozeParameters;
 
     private double mQqsSplitFraction;
 
@@ -454,18 +455,15 @@
     @Inject
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             InjectionInflationController injectionInflationController,
-            NotificationWakeUpCoordinator coordinator,
-            PulseExpansionHandler pulseExpansionHandler,
+            NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
             DynamicPrivacyController dynamicPrivacyController,
-            KeyguardBypassController bypassController,
-            FalsingManager falsingManager,
-            PluginManager pluginManager,
-            ShadeController shadeController,
+            KeyguardBypassController bypassController, FalsingManager falsingManager,
+            PluginManager pluginManager, ShadeController shadeController,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             NotificationEntryManager notificationEntryManager,
             KeyguardStateController keyguardStateController,
-            StatusBarStateController statusBarStateController,
-            DozeLog dozeLog) {
+            StatusBarStateController statusBarStateController, DozeLog dozeLog,
+            DozeParameters dozeParameters) {
         super(context, attrs, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController);
         setWillNotDraw(!DEBUG);
@@ -480,6 +478,7 @@
         mCommandQueue = getComponent(context, CommandQueue.class);
         mDisplayId = context.getDisplayId();
         mPulseExpansionHandler = pulseExpansionHandler;
+        mDozeParameters = dozeParameters;
         pulseExpansionHandler.setPulseExpandAbortListener(() -> {
             if (mQs != null) {
                 mQs.animateHeaderSlidingOut();
@@ -3435,9 +3434,8 @@
 
     public void setPulsing(boolean pulsing) {
         mPulsing = pulsing;
-        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
-        final boolean animatePulse = !dozeParameters.getDisplayNeedsBlanking()
-                && dozeParameters.getAlwaysOn();
+        final boolean animatePulse = !mDozeParameters.getDisplayNeedsBlanking()
+                && mDozeParameters.getAlwaysOn();
         if (animatePulse) {
             mAnimateNextPositionUpdate = true;
         }
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 d1fe46e..c092f9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -387,6 +387,7 @@
     private final ConfigurationController mConfigurationController;
     private final StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
     private final NotifLog mNotifLog;
+    private final DozeParameters mDozeParameters;
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -497,8 +498,7 @@
             WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
             final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
-            final boolean imageWallpaperInAmbient =
-                    !DozeParameters.getInstance(mContext).getDisplayNeedsBlanking();
+            final boolean imageWallpaperInAmbient = !mDozeParameters.getDisplayNeedsBlanking();
             // If WallpaperInfo is null, it must be ImageWallpaper.
             final boolean supportsAmbientMode = deviceSupportsAodWallpaper
                     && ((info == null && imageWallpaperInAmbient)
@@ -674,7 +674,8 @@
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
             StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
-            NotifLog notifLog) {
+            NotifLog notifLog,
+            DozeParameters dozeParameters) {
         super(context);
         mLightBarController = lightBarController;
         mAutoHideController = autoHideController;
@@ -730,6 +731,7 @@
         mStatusBarWindowController = statusBarWindowController;
         mStatusBarWindowViewControllerBuilder = statusBarWindowViewControllerBuilder;
         mNotifLog = notifLog;
+        mDozeParameters = dozeParameters;
 
         mBubbleExpandListener =
                 (isExpanding, key) -> {
@@ -750,7 +752,7 @@
         KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
         if (sliceProvider != null) {
             sliceProvider.initDependencies(mMediaManager, mStatusBarStateController,
-                    mKeyguardBypassController, DozeParameters.getInstance(mContext));
+                    mKeyguardBypassController, mDozeParameters);
         } else {
             Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
         }
@@ -1032,13 +1034,12 @@
                     if (mStatusBarWindow != null) {
                         mStatusBarWindowViewController.onScrimVisibilityChanged(scrimsVisible);
                     }
-                }, DozeParameters.getInstance(mContext),
+                }, mDozeParameters,
                 mContext.getSystemService(AlarmManager.class),
                 mKeyguardStateController);
         mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
                 mHeadsUpManager, mNotificationIconAreaController, mScrimController);
-        mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context),
-                mDozeLog);
+        mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog);
 
         BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop);
         mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
@@ -1343,7 +1344,7 @@
         mBiometricUnlockController = new BiometricUnlockController(mContext,
                 mDozeScrimController, mKeyguardViewMediator,
                 mScrimController, this, mKeyguardStateController, new Handler(),
-                mKeyguardUpdateMonitor, mKeyguardBypassController);
+                mKeyguardUpdateMonitor, mKeyguardBypassController, mDozeParameters);
         putComponent(BiometricUnlockController.class, mBiometricUnlockController);
         mStatusBarKeyguardViewManager = mKeyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
@@ -3571,8 +3572,7 @@
         mDozing = isDozing;
 
         // Collapse the notification panel if open
-        boolean dozingAnimated = mDozingRequested
-                && DozeParameters.getInstance(mContext).shouldControlScreenOff();
+        boolean dozingAnimated = mDozingRequested && mDozeParameters.shouldControlScreenOff();
         mNotificationPanel.resetViews(dozingAnimated);
 
         updateQsExpansionEnabled();
@@ -3828,7 +3828,7 @@
      */
     private void updateNotificationPanelTouchState() {
         boolean goingToSleepWithoutAnimation = isGoingToSleep()
-                && !DozeParameters.getInstance(mContext).shouldControlScreenOff();
+                && !mDozeParameters.shouldControlScreenOff();
         boolean disabled = (!mDeviceInteractive && !mPulsing) || goingToSleepWithoutAnimation;
         mNotificationPanel.setTouchAndAnimationDisabled(disabled);
         mNotificationIconAreaController.setAnimationsEnabled(!disabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 724b462..ca7a936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -21,7 +21,6 @@
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 
-import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -39,8 +38,6 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -94,24 +91,14 @@
     private final ArrayList<WeakReference<StatusBarWindowCallback>>
             mCallbacks = Lists.newArrayList();
 
-    private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+    private final SysuiColorExtractor mColorExtractor;
 
     @Inject
-    public StatusBarWindowController(Context context,
-            StatusBarStateController statusBarStateController,
-            ConfigurationController configurationController,
-            KeyguardBypassController keyguardBypassController) {
-        this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(),
-                DozeParameters.getInstance(context), statusBarStateController,
-                configurationController, keyguardBypassController);
-    }
-
-    @VisibleForTesting
     public StatusBarWindowController(Context context, WindowManager windowManager,
             IActivityManager activityManager, DozeParameters dozeParameters,
             StatusBarStateController statusBarStateController,
             ConfigurationController configurationController,
-            KeyguardBypassController keyguardBypassController) {
+            KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor) {
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
@@ -120,6 +107,7 @@
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
         mLpChanged = new LayoutParams();
         mKeyguardBypassController = keyguardBypassController;
+        mColorExtractor = colorExtractor;
         mLockScreenDisplayTimeout = context.getResources()
                 .getInteger(R.integer.config_lockScreenDisplayTimeout);
         ((SysuiStatusBarStateController) statusBarStateController)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index 1ce7763..fd3f9c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -93,7 +93,8 @@
             NotificationEntryManager notificationEntryManager,
             KeyguardStateController keyguardStateController,
             SysuiStatusBarStateController statusBarStateController,
-            DozeLog dozeLog) {
+            DozeLog dozeLog,
+            DozeParameters dozeParameters) {
         mView = view;
         mFalsingManager = falsingManager;
 
@@ -113,7 +114,8 @@
                 notificationEntryManager,
                 keyguardStateController,
                 statusBarStateController,
-                dozeLog);
+                dozeLog,
+                dozeParameters);
         ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
         notificationPanelView.setVisibility(View.INVISIBLE);
@@ -485,6 +487,7 @@
         private final NotificationLockscreenUserManager mNotificationLockScreenUserManager;
         private final NotificationEntryManager mNotificationEntryManager;
         private final DozeLog mDozeLog;
+        private final DozeParameters mDozeParameters;
         private StatusBarWindowView mView;
 
         @Inject
@@ -501,7 +504,8 @@
                 NotificationEntryManager notificationEntryManager,
                 KeyguardStateController keyguardStateController,
                 StatusBarStateController statusBarStateController,
-                DozeLog dozeLog) {
+                DozeLog dozeLog,
+                DozeParameters dozeParameters) {
             mInjectionInflationController = injectionInflationController;
             mCoordinator = coordinator;
             mPulseExpansionHandler = pulseExpansionHandler;
@@ -515,6 +519,7 @@
             mKeyguardStateController = keyguardStateController;
             mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
             mDozeLog = dozeLog;
+            mDozeParameters = dozeParameters;
         }
 
         /**
@@ -552,7 +557,8 @@
                     mNotificationEntryManager,
                     mKeyguardStateController,
                     mStatusBarStateController,
-                    mDozeLog);
+                    mDozeLog,
+                    mDozeParameters);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 95ae23c..bcfbdac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -314,7 +314,6 @@
         // adb shell settings put system enable_fullscreen_user_switcher 1  # Turn it on.
         // Restart SystemUI or adb reboot.
         final int DEFAULT = -1;
-        // TODO(b/140061064)
         final int overrideUseFullscreenUserSwitcher =
                 whitelistIpcs(() -> Settings.System.getInt(mContext.getContentResolver(),
                         "enable_fullscreen_user_switcher", DEFAULT));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
new file mode 100644
index 0000000..a601e9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
@@ -0,0 +1,8 @@
+# Android TV Core Framework
+rgl@google.com
+valiiftime@google.com
+galinap@google.com
+patrikf@google.com
+robhor@google.com
+sergeynv@google.com
+
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 0a3e34e..fd99ef3 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.PermissionChecker;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.hardware.usb.IUsbManager;
@@ -63,6 +64,7 @@
         mDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
         mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
         mResolveInfo = (ResolveInfo) intent.getParcelableExtra("rinfo");
+        String packageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
 
         PackageManager packageManager = getPackageManager();
         String appName = mResolveInfo.loadLabel(packageManager).toString();
@@ -74,8 +76,20 @@
                     mAccessory.getDescription());
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
         } else {
-            ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName,
-                    mDevice.getProductName());
+            int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+            boolean hasRecordPermission =
+                    PermissionChecker.checkPermissionForPreflight(
+                            this, android.Manifest.permission.RECORD_AUDIO, -1, uid,
+                            packageName)
+                            == android.content.pm.PackageManager.PERMISSION_GRANTED;
+            boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
+            boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
+
+            int strID = useRecordWarning
+                    ? R.string.usb_device_confirm_prompt_warn
+                    : R.string.usb_device_confirm_prompt;
+
+            ap.mMessage = getString(strID, appName, mDevice.getProductName());
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
         }
         ap.mPositiveButtonText = getString(android.R.string.ok);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index dd5211d..3472573 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -56,8 +56,10 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.colorextraction.ColorExtractor;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -141,6 +143,10 @@
     private BubbleController.BubbleExpandListener mBubbleExpandListener;
     @Mock
     private PendingIntent mDeleteIntent;
+    @Mock
+    private SysuiColorExtractor mColorExtractor;
+    @Mock
+    ColorExtractor.GradientColors mGradientColors;
 
     private BubbleData mBubbleData;
 
@@ -150,11 +156,12 @@
         mStatusBarView = new FrameLayout(mContext);
         mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
         mContext.addMockSystemService(FaceManager.class, mFaceManager);
+        when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
                 mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor);
         mStatusBarWindowController.add(mStatusBarView, 120 /* height */);
 
         // Need notifications for bubbles
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
index d011e48..3ba5d1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.systemui.classifier.Classifier.UNLOCK;
+
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 
@@ -42,6 +44,7 @@
         displayMetrics.widthPixels = 1000;
         displayMetrics.heightPixels = 1000;
         mDataProvider = new FalsingDataProvider(displayMetrics);
+        mDataProvider.setInteractionType(UNLOCK);
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
index 341b74b..96b2028 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 
@@ -74,4 +76,21 @@
         motionEvent.recycle();
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
+
+    @Test
+    public void testPass_multiPointerDragDown() {
+        MotionEvent.PointerProperties[] pointerProperties =
+                MotionEvent.PointerProperties.createArray(2);
+        pointerProperties[0].id = 0;
+        pointerProperties[1].id = 1;
+        MotionEvent.PointerCoords[] pointerCoords = MotionEvent.PointerCoords.createArray(2);
+        MotionEvent motionEvent = MotionEvent.obtain(
+                1, 1, MotionEvent.ACTION_DOWN, 2, pointerProperties, pointerCoords, 0, 0, 0, 0, 0,
+                0,
+                0, 0);
+        mClassifier.onTouchEvent(motionEvent);
+        motionEvent.recycle();
+        getDataProvider().setInteractionType(QUICK_SETTINGS);
+        assertThat(mClassifier.isFalseTouch(), is(false));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
new file mode 100644
index 0000000..4becd52
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.qs.external
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ServiceInfo
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.service.quicksettings.IQSTileService
+import android.service.quicksettings.Tile
+import android.test.suitebuilder.annotation.SmallTest
+import android.view.IWindowManager
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.QSTileHost
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CustomTileTest : SysuiTestCase() {
+
+    companion object {
+        const val packageName = "test_package"
+        const val className = "test_class"
+        val componentName = ComponentName(packageName, className)
+        val TILE_SPEC = CustomTile.toSpec(componentName)
+    }
+
+    @Mock private lateinit var mTileHost: QSTileHost
+    @Mock private lateinit var mTileService: IQSTileService
+    @Mock private lateinit var mTileServices: TileServices
+    @Mock private lateinit var mTileServiceManager: TileServiceManager
+    @Mock private lateinit var mWindowService: IWindowManager
+    @Mock private lateinit var mPackageManager: PackageManager
+    @Mock private lateinit var mApplicationInfo: ApplicationInfo
+    @Mock private lateinit var mServiceInfo: ServiceInfo
+
+    private lateinit var customTile: CustomTile
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        mContext.addMockSystemService("window", mWindowService)
+        mContext.setMockPackageManager(mPackageManager)
+        `when`(mTileHost.tileServices).thenReturn(mTileServices)
+        `when`(mTileHost.context).thenReturn(mContext)
+        `when`(mTileServices.getTileWrapper(any(CustomTile::class.java)))
+                .thenReturn(mTileServiceManager)
+        `when`(mTileServiceManager.tileService).thenReturn(mTileService)
+        `when`(mPackageManager.getApplicationInfo(anyString(), anyInt()))
+                .thenReturn(mApplicationInfo)
+
+        `when`(mPackageManager.getServiceInfo(any(ComponentName::class.java), anyInt()))
+                .thenReturn(mServiceInfo)
+        mServiceInfo.applicationInfo = mApplicationInfo
+
+        customTile = CustomTile.create(mTileHost, TILE_SPEC)
+    }
+
+    @Test
+    fun testBooleanTileHasBooleanState() {
+        `when`(mTileServiceManager.isBooleanTile).thenReturn(true)
+        customTile = CustomTile.create(mTileHost, TILE_SPEC)
+
+        assertTrue(customTile.state is QSTile.BooleanState)
+        assertTrue(customTile.newTileState() is QSTile.BooleanState)
+    }
+
+    @Test
+    fun testRegularTileHasNotBooleanState() {
+        assertFalse(customTile.state is QSTile.BooleanState)
+        assertFalse(customTile.newTileState() is QSTile.BooleanState)
+    }
+
+    @Test
+    fun testValueUpdatedInBooleanTile() {
+        `when`(mTileServiceManager.isBooleanTile).thenReturn(true)
+        customTile = CustomTile.create(mTileHost, TILE_SPEC)
+        customTile.qsTile.icon = mock(Icon::class.java)
+        `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java)))
+                .thenReturn(mock(Drawable::class.java))
+
+        val state = customTile.newTileState()
+        assertTrue(state is QSTile.BooleanState)
+
+        customTile.qsTile.state = Tile.STATE_INACTIVE
+        customTile.handleUpdateState(state, null)
+        assertFalse((state as QSTile.BooleanState).value)
+
+        customTile.qsTile.state = Tile.STATE_ACTIVE
+        customTile.handleUpdateState(state, null)
+        assertTrue(state.value)
+
+        customTile.qsTile.state = Tile.STATE_UNAVAILABLE
+        customTile.handleUpdateState(state, null)
+        assertFalse(state.value)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index f35295c..11b0c69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -101,6 +101,7 @@
             defaultServiceInfo = new ServiceInfo();
             defaultServiceInfo.metaData = new Bundle();
             defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true);
+            defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_BOOLEAN_TILE, true);
         }
         when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt()))
                 .thenReturn(defaultServiceInfo);
@@ -237,4 +238,9 @@
         verifyBind(2);
         verify(mMockTileService, times(2)).onStartListening();
     }
+
+    @Test
+    public void testBooleanTile() throws Exception {
+        assertTrue(mStateManager.isBooleanTile());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index ff9aae7..72bea56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -76,6 +76,8 @@
     private Handler mHandler;
     @Mock
     private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private DozeParameters mDozeParameters;
     private BiometricUnlockController mBiometricUnlockController;
 
     @Before
@@ -92,7 +94,8 @@
                 mStatusBarWindowController);
         mBiometricUnlockController = new BiometricUnlockController(mContext, mDozeScrimController,
                 mKeyguardViewMediator, mScrimController, mStatusBar, mKeyguardStateController,
-                mHandler, mUpdateMonitor, 0 /* wakeUpDelay */, mKeyguardBypassController);
+                mHandler, mUpdateMonitor, 0 /* wakeUpDelay */, mKeyguardBypassController,
+                mDozeParameters);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 60050b1..debc840 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -17,68 +17,73 @@
 package com.android.systemui.statusbar.phone;
 
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
-import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.PowerManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.doze.DozeScreenState;
+import com.android.systemui.tuner.TunerService;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DozeParametersTest extends SysuiTestCase {
 
+    private DozeParameters mDozeParameters;
+
+    @Mock Resources mResources;
+    @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+    @Mock private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
+    @Mock private PowerManager mPowerManager;
+    @Mock private TunerService mTunerService;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDozeParameters = new DozeParameters(
+            mResources,
+            mAmbientDisplayConfiguration,
+            mAlwaysOnDisplayPolicy,
+            mPowerManager,
+            mTunerService
+        );
+    }
     @Test
     public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
-        TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
-        PowerManager mockedPowerManager = dozeParameters.getPowerManager();
-        dozeParameters.setControlScreenOffAnimation(true);
-        reset(mockedPowerManager);
-        dozeParameters.setControlScreenOffAnimation(false);
-        verify(mockedPowerManager).setDozeAfterScreenOff(eq(true));
+        mDozeParameters.setControlScreenOffAnimation(true);
+        reset(mPowerManager);
+        mDozeParameters.setControlScreenOffAnimation(false);
+        verify(mPowerManager).setDozeAfterScreenOff(eq(true));
     }
 
     @Test
     public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_true() {
-        TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
-        PowerManager mockedPowerManager = dozeParameters.getPowerManager();
-        dozeParameters.setControlScreenOffAnimation(false);
-        reset(mockedPowerManager);
-        dozeParameters.setControlScreenOffAnimation(true);
-        verify(dozeParameters.getPowerManager()).setDozeAfterScreenOff(eq(false));
+        mDozeParameters.setControlScreenOffAnimation(false);
+        reset(mPowerManager);
+        mDozeParameters.setControlScreenOffAnimation(true);
+        verify(mPowerManager).setDozeAfterScreenOff(eq(false));
     }
 
     @Test
     public void test_getWallpaperAodDuration_when_shouldControlScreenOff() {
-        TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
-        dozeParameters.setControlScreenOffAnimation(true);
-        Assert.assertEquals("wallpaper hides faster when controlling screen off",
-                dozeParameters.getWallpaperAodDuration(),
+        mDozeParameters.setControlScreenOffAnimation(true);
+        Assert.assertEquals(
+                "wallpaper hides faster when controlling screen off",
+                mDozeParameters.getWallpaperAodDuration(),
                 DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY);
     }
-
-    private class TestableDozeParameters extends DozeParameters {
-        private PowerManager mPowerManager;
-
-        TestableDozeParameters(Context context) {
-            super(context);
-            mPowerManager = mock(PowerManager.class);
-        }
-
-        @Override
-        protected PowerManager getPowerManager() {
-            return mPowerManager;
-        }
-    }
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 2c19037..cff6635 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -116,6 +116,7 @@
     private FalsingManager mFalsingManager;
     @Mock
     private KeyguardBypassController mKeyguardBypassController;
+    @Mock private DozeParameters mDozeParameters;
     private NotificationPanelView mNotificationPanelView;
 
     @Before
@@ -130,10 +131,11 @@
         mDependency.injectMockDependency(ConfigurationController.class);
         mDependency.injectMockDependency(ZenModeController.class);
         NotificationWakeUpCoordinator coordinator =
-                new NotificationWakeUpCoordinator(mContext,
+                new NotificationWakeUpCoordinator(
                         mock(HeadsUpManagerPhone.class),
                         new StatusBarStateControllerImpl(),
-                        mKeyguardBypassController);
+                        mKeyguardBypassController,
+                        mDozeParameters);
         PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
                 mContext,
                 coordinator,
@@ -239,7 +241,8 @@
                             mock(NotifLog.class)),
                     mock(KeyguardStateController.class),
                     statusBarStateController,
-                    mock(DozeLog.class));
+                    mock(DozeLog.class),
+                    mDozeParameters);
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f76dc61..8f1b6017 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -220,6 +220,7 @@
     @Mock private StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
     @Mock private StatusBarWindowViewController mStatusBarWindowViewController;
     @Mock private NotifLog mNotifLog;
+    @Mock private DozeParameters mDozeParameters;
 
     @Before
     public void setup() throws Exception {
@@ -343,7 +344,8 @@
                 configurationController,
                 mStatusBarWindowController,
                 mStatusBarWindowViewControllerBuilder,
-                mNotifLog);
+                mNotifLog,
+                mDozeParameters);
         // TODO: we should be able to call mStatusBar.start() and have all the below values
         // initialized automatically.
         mStatusBar.mComponents = mContext.getComponents();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index 4ffaeae..a21a658 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -32,7 +32,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.colorextraction.ColorExtractor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
@@ -48,20 +50,15 @@
 @SmallTest
 public class StatusBarWindowControllerTest extends SysuiTestCase {
 
-    @Mock
-    private WindowManager mWindowManager;
-    @Mock
-    private DozeParameters mDozeParameters;
-    @Mock
-    private ViewGroup mStatusBarView;
-    @Mock
-    private IActivityManager mActivityManager;
-    @Mock
-    private SysuiStatusBarStateController mStatusBarStateController;
-    @Mock
-    private ConfigurationController mConfigurationController;
-    @Mock
-    private KeyguardBypassController mKeyguardBypassController;
+    @Mock private WindowManager mWindowManager;
+    @Mock private DozeParameters mDozeParameters;
+    @Mock private ViewGroup mStatusBarView;
+    @Mock private IActivityManager mActivityManager;
+    @Mock private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock private ConfigurationController mConfigurationController;
+    @Mock private KeyguardBypassController mKeyguardBypassController;
+    @Mock private SysuiColorExtractor mColorExtractor;
+    @Mock ColorExtractor.GradientColors mGradientColors;
 
     private StatusBarWindowController mStatusBarWindowController;
 
@@ -69,10 +66,11 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+        when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
                 mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController);
+                mConfigurationController, mKeyguardBypassController, mColorExtractor);
         mStatusBarWindowController.add(mStatusBarView, 100 /* height */);
     }
 
@@ -96,9 +94,6 @@
 
     @Test
     public void testOnThemeChanged_doesntCrash() {
-        mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.onThemeChanged();
     }
 
@@ -109,9 +104,6 @@
 
     @Test
     public void testSetForcePluginOpen_beforeStatusBarInitialization() {
-        mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
-                mActivityManager, mDozeParameters, mStatusBarStateController,
-                mConfigurationController, mKeyguardBypassController);
         mStatusBarWindowController.setForcePluginOpen(true);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 0ef1acc..7c1dfa6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -70,6 +70,7 @@
     @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private StatusBar mStatusBar;
     @Mock private DozeLog mDozeLog;
+    @Mock private DozeParameters mDozeParameters;
 
     @Before
     public void setUp() {
@@ -94,7 +95,8 @@
                 mNotificationEntryManager,
                 mKeyguardStateController,
                 mStatusBarStateController,
-                mDozeLog)
+                mDozeLog,
+                mDozeParameters)
                 .setShadeController(mShadeController)
                 .setStatusBarWindowView(mView)
                 .build();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e909e7a..68e11df32 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -366,9 +366,11 @@
                     if (userId != mCurrentUserId) {
                         return;
                     }
-                    AccessibilityUserState userState = getUserStateLocked(userId);
-                    boolean reboundAService = userState.getBindingServicesLocked().removeIf(
+                    final AccessibilityUserState userState = getUserStateLocked(userId);
+                    final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
                             component -> component != null
+                                    && component.getPackageName().equals(packageName))
+                            || userState.mCrashedServices.removeIf(component -> component != null
                                     && component.getPackageName().equals(packageName));
                     if (reboundAService) {
                         onUserStateChangedLocked(userState);
@@ -393,6 +395,7 @@
                         if (compPkg.equals(packageName)) {
                             it.remove();
                             userState.getBindingServicesLocked().remove(comp);
+                            userState.getCrashedServicesLocked().remove(comp);
                             // Update the enabled services setting.
                             persistComponentNamesToSettingLocked(
                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
@@ -753,6 +756,7 @@
             userState.mEnabledServices.clear();
             userState.mEnabledServices.add(service);
             userState.getBindingServicesLocked().clear();
+            userState.getCrashedServicesLocked().clear();
             userState.mTouchExplorationGrantedServices.clear();
             userState.mTouchExplorationGrantedServices.add(service);
 
@@ -1178,6 +1182,10 @@
             AccessibilityServiceInfo accessibilityServiceInfo;
             try {
                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
+                if (userState.mCrashedServices.contains(serviceInfo.getComponentName())) {
+                    // Restore the crashed attribute.
+                    accessibilityServiceInfo.crashed = true;
+                }
                 mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
             } catch (XmlPullParserException | IOException xppe) {
                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
@@ -1418,8 +1426,9 @@
                 continue;
             }
 
-            // Wait for the binding if it is in process.
-            if (userState.getBindingServicesLocked().contains(componentName)) {
+            // Skip the component since it may be in process or crashed.
+            if (userState.getBindingServicesLocked().contains(componentName)
+                    || userState.getCrashedServicesLocked().contains(componentName)) {
                 continue;
             }
             if (userState.mEnabledServices.contains(componentName)
@@ -2687,6 +2696,7 @@
                     }
                 } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
                     if (readEnabledAccessibilityServicesLocked(userState)) {
+                        userState.updateCrashedServicesIfNeededLocked();
                         onUserStateChangedLocked(userState);
                     }
                 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index d154060..a0a755a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -62,9 +62,6 @@
 
     private final Handler mMainHandler;
 
-    private boolean mWasConnectedAndDied;
-
-
     AccessibilityServiceConnection(AccessibilityUserState userState, Context context,
             ComponentName componentName,
             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
@@ -168,8 +165,6 @@
 
     @Override
     public AccessibilityServiceInfo getServiceInfo() {
-        // Update crashed data
-        mAccessibilityServiceInfo.crashed = mWasConnectedAndDied;
         return mAccessibilityServiceInfo;
     }
 
@@ -178,10 +173,13 @@
         synchronized (mLock) {
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState == null) return;
-            Set<ComponentName> bindingServices = userState.getBindingServicesLocked();
-            if (bindingServices.contains(mComponentName) || mWasConnectedAndDied) {
+            final Set<ComponentName> bindingServices = userState.getBindingServicesLocked();
+            final Set<ComponentName> crashedServices = userState.getCrashedServicesLocked();
+            if (bindingServices.contains(mComponentName)
+                    || crashedServices.contains(mComponentName)) {
                 bindingServices.remove(mComponentName);
-                mWasConnectedAndDied = false;
+                crashedServices.remove(mComponentName);
+                mAccessibilityServiceInfo.crashed = false;
                 serviceInterface = mServiceInterface;
             }
             // There's a chance that service is removed from enabled_accessibility_services setting
@@ -271,7 +269,7 @@
             if (!isConnectedLocked()) {
                 return;
             }
-            mWasConnectedAndDied = true;
+            mAccessibilityServiceInfo.crashed = true;
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState != null) {
                 userState.serviceDisconnectedLocked(this);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 69f1e0e..a0b9866 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -73,6 +73,8 @@
 
     final Set<ComponentName> mBindingServices = new HashSet<>();
 
+    final Set<ComponentName> mCrashedServices = new HashSet<>();
+
     final Set<ComponentName> mEnabledServices = new HashSet<>();
 
     final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();
@@ -127,6 +129,7 @@
         // Clear service management state.
         mBoundServices.clear();
         mBindingServices.clear();
+        mCrashedServices.clear();
 
         // Clear event management state.
         mLastSentClientState = -1;
@@ -184,15 +187,16 @@
 
     /**
      * Make sure a services disconnected but still 'on' state is reflected in AccessibilityUserState
-     * There are three states to a service here: off, bound, and binding.
-     * This drops a service from a bound state, to the binding state.
-     * The binding state describes the situation where a service is on, but not bound.
+     * There are four states to a service here: off, bound, and binding, and crashed.
+     * This drops a service from a bound state, to the crashed state.
+     * The crashed state describes the situation where a service used to be bound, but no longer is
+     * despite still being enabled.
      *
      * @param serviceConnection The service.
      */
     void serviceDisconnectedLocked(AccessibilityServiceConnection serviceConnection) {
         removeServiceLocked(serviceConnection);
-        mBindingServices.add(serviceConnection.getComponentName());
+        mCrashedServices.add(serviceConnection.getComponentName());
     }
 
     /**
@@ -289,17 +293,44 @@
         mBindInstantServiceAllowed = allowed;
     }
 
+    /**
+     * Returns binding service list.
+     */
     Set<ComponentName> getBindingServicesLocked() {
         return mBindingServices;
     }
 
     /**
+     * Returns crashed service list.
+     */
+    Set<ComponentName> getCrashedServicesLocked() {
+        return mCrashedServices;
+    }
+
+    /**
      * Returns enabled service list.
      */
     Set<ComponentName> getEnabledServicesLocked() {
         return mEnabledServices;
     }
 
+    /**
+     * Remove service from crashed service list if users disable it.
+     */
+    void updateCrashedServicesIfNeededLocked() {
+        for (int i = 0, count = mInstalledServices.size(); i < count; i++) {
+            final AccessibilityServiceInfo installedService = mInstalledServices.get(i);
+            final ComponentName componentName = ComponentName.unflattenFromString(
+                    installedService.getId());
+
+            if (mCrashedServices.contains(componentName)
+                    && !mEnabledServices.contains(componentName)) {
+                // Remove it from mCrashedServices since users toggle the switch bar to retry.
+                mCrashedServices.remove(componentName);
+            }
+        }
+    }
+
     List<AccessibilityServiceConnection> getBoundServicesLocked() {
         return mBoundServices;
     }
@@ -439,6 +470,18 @@
                 pw.append(componentName.toShortString());
             }
         }
+        pw.println("}");
+        pw.append("     Crashed services:{");
+        it = mCrashedServices.iterator();
+        if (it.hasNext()) {
+            ComponentName componentName = it.next();
+            pw.append(componentName.toShortString());
+            while (it.hasNext()) {
+                componentName = it.next();
+                pw.append(", ");
+                pw.append(componentName.toShortString());
+            }
+        }
         pw.println("}]");
     }
 
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index e5e11ea..ac006df 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -239,7 +239,6 @@
     private final KeyValueBackupReporter mReporter;
     private final OnTaskFinishedListener mTaskFinishedListener;
     private final boolean mUserInitiated;
-    private final boolean mNonIncremental;
     private final int mCurrentOpToken;
     private final int mUserId;
     private final File mStateDirectory;
@@ -264,6 +263,7 @@
     // and at least one of the packages had data. Used to avoid updating current token for
     // empty backups.
     private boolean mHasDataToBackup;
+    private boolean mNonIncremental;
 
     /**
      * This {@link ConditionVariable} is used to signal that the cancel operation has been
@@ -412,6 +412,11 @@
         try {
             IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.startTask()");
             String transportName = transport.name();
+            if (transportName.contains("EncryptedLocalTransport")) {
+                // Temporary code for EiTF POC. Only supports non-incremental backups.
+                mNonIncremental = true;
+            }
+
             mReporter.onTransportReady(transportName);
 
             // If we haven't stored PM metadata yet, we must initialize the transport.
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index c8dbb36..27824af 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,11 +18,13 @@
 
 import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.service.contentcapture.ContentCaptureService.setClientState;
 import static android.view.contentcapture.ContentCaptureHelper.toList;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_TRUE;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
 
 import static com.android.internal.util.SyncResultReceiver.bundleFor;
 
@@ -520,6 +522,17 @@
         return true;
     }
 
+    @GuardedBy("mLock")
+    private boolean isDefaultServiceLocked(int userId) {
+        final String defaultServiceName = mServiceNameResolver.getDefaultServiceName(userId);
+        if (defaultServiceName == null) {
+            return false;
+        }
+
+        final String currentServiceName = mServiceNameResolver.getServiceName(userId);
+        return defaultServiceName.equals(currentServiceName);
+    }
+
     @Override // from AbstractMasterSystemService
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
@@ -557,6 +570,10 @@
 
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                if (!isDefaultServiceLocked(userId) && !isCalledByServiceLocked("startSession()")) {
+                    setClientState(result, STATE_DISABLED, /* binder= */ null);
+                    return;
+                }
                 service.startSessionLocked(activityToken, activityPresentationInfo, sessionId,
                         Binder.getCallingUid(), flags, result);
             }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 9a97ddb..b41e95f 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -47,6 +47,7 @@
 import android.content.pm.PermissionInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -1564,6 +1565,7 @@
                     Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
 
             mClockReceiver = mInjector.getClockReceiver(this);
+            new ChargingReceiver();
             new InteractiveStateReceiver();
             new UninstallReceiver();
 
@@ -4148,7 +4150,7 @@
         public static final int LISTENER_TIMEOUT = 3;
         public static final int REPORT_ALARMS_ACTIVE = 4;
         public static final int APP_STANDBY_BUCKET_CHANGED = 5;
-        public static final int APP_STANDBY_PAROLE_CHANGED = 6;
+        public static final int CHARGING_STATUS_CHANGED = 6;
         public static final int REMOVE_FOR_STOPPED = 7;
         public static final int UNREGISTER_CANCEL_LISTENER = 8;
 
@@ -4206,7 +4208,7 @@
                     }
                     break;
 
-                case APP_STANDBY_PAROLE_CHANGED:
+                case CHARGING_STATUS_CHANGED:
                     synchronized (mLock) {
                         mAppStandbyParole = (Boolean) msg.obj;
                         if (reorderAlarmsBasedOnStandbyBuckets(null)) {
@@ -4247,6 +4249,37 @@
         }
     }
 
+    @VisibleForTesting
+    class ChargingReceiver extends BroadcastReceiver {
+        ChargingReceiver() {
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(BatteryManager.ACTION_CHARGING);
+            filter.addAction(BatteryManager.ACTION_DISCHARGING);
+            getContext().registerReceiver(this, filter);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final boolean charging;
+            if (BatteryManager.ACTION_CHARGING.equals(action)) {
+                if (DEBUG_STANDBY) {
+                    Slog.d(TAG, "Device is charging.");
+                }
+                charging = true;
+            } else {
+                if (DEBUG_STANDBY) {
+                    Slog.d(TAG, "Disconnected from power.");
+                }
+                charging = false;
+            }
+            mHandler.removeMessages(AlarmHandler.CHARGING_STATUS_CHANGED);
+            mHandler.obtainMessage(AlarmHandler.CHARGING_STATUS_CHANGED, charging)
+                    .sendToTarget();
+        }
+    }
+
+    @VisibleForTesting
     class ClockReceiver extends BroadcastReceiver {
         public ClockReceiver() {
             IntentFilter filter = new IntentFilter();
@@ -4429,7 +4462,7 @@
 
         @Override public void onUidCachedChanged(int uid, boolean cached) {
         }
-    };
+    }
 
     /**
      * Tracking of app assignments to standby buckets
@@ -4447,18 +4480,7 @@
             mHandler.obtainMessage(AlarmHandler.APP_STANDBY_BUCKET_CHANGED, userId, -1, packageName)
                     .sendToTarget();
         }
-
-        @Override
-        public void onParoleStateChanged(boolean isParoleOn) {
-            if (DEBUG_STANDBY) {
-                Slog.d(TAG, "Global parole state now " + (isParoleOn ? "ON" : "OFF"));
-            }
-            mHandler.removeMessages(AlarmHandler.APP_STANDBY_BUCKET_CHANGED);
-            mHandler.removeMessages(AlarmHandler.APP_STANDBY_PAROLE_CHANGED);
-            mHandler.obtainMessage(AlarmHandler.APP_STANDBY_PAROLE_CHANGED,
-                    Boolean.valueOf(isParoleOn)).sendToTarget();
-        }
-    };
+    }
 
     private final Listener mForceAppStandbyListener = new Listener() {
         @Override
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 2c67c50..da760b6 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -71,8 +71,7 @@
  * - Temporary power save whitelist
  * - Global "force all apps standby" mode enforced by battery saver.
  *
- * Test:
-  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
+ * Test: atest com.android.server.AppStateTrackerTest
  */
 public class AppStateTracker {
     private static final String TAG = "AppStateTracker";
@@ -710,10 +709,6 @@
                 mHandler.notifyExemptChanged();
             }
         }
-
-        @Override
-        public void onParoleStateChanged(boolean isParoleOn) {
-        }
     }
 
     private Listener[] cloneListeners() {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 1a5dac5..e9d2b31 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -18,6 +18,23 @@
                     "include-filter": "com.android.server.appop"
                 }
             ]
+        },
+        {
+            "name": "CtsPermissionTestCases",
+            "options": [
+                {
+                    "include-filter": "android.permission.cts.BackgroundPermissionsTest"
+                },
+                {
+                    "include-filter": "android.permission.cts.SplitPermissionTest"
+                },
+                {
+                    "include-filter": "android.permission.cts.PermissionFlagsTest"
+                },
+                {
+                    "include-filter": "android.permission.cts.SharedUidPermissionsTest"
+                }
+            ]
         }
     ]
 }
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index b4c7dd3..080e6ce 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -333,7 +333,8 @@
         current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
         current.mPortId = getPortId(current.mPhysicalAddress);
         current.mDeviceType = params[2] & 0xFF;
-        current.mDisplayName = HdmiUtils.getDefaultDeviceName(current.mDeviceType);
+        // Keep display name empty. TIF fallbacks to the service label provided by the package mg.
+        current.mDisplayName = "";
 
         // This is to manager CEC device separately in case they don't have address.
         if (mIsTvDevice) {
@@ -359,17 +360,13 @@
             return;
         }
 
-        String displayName = null;
+        String displayName = "";
         try {
-            if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT) {
-                displayName = HdmiUtils.getDefaultDeviceName(current.mLogicalAddress);
-            } else {
+            if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) {
                 displayName = new String(cmd.getParams(), "US-ASCII");
             }
         } catch (UnsupportedEncodingException e) {
             Slog.w(TAG, "Failed to decode display name: " + cmd.toString());
-            // If failed to get display name, use the default name of device.
-            displayName = HdmiUtils.getDefaultDeviceName(current.mLogicalAddress);
         }
         current.mDisplayName = displayName;
         increaseProcessedDeviceCount();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 211d028..dde873b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -489,7 +489,7 @@
         if (oldDevice == null || oldDevice.getPhysicalAddress() != path) {
             addCecDevice(new HdmiDeviceInfo(
                     address, path, mService.pathToPortId(path), type,
-                    Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(address)));
+                    Constants.UNKNOWN_VENDOR_ID, ""));
             // if we are adding a new device info, send out a give osd name command
             // to update the name of the device in TIF
             mService.sendCecCommand(
@@ -526,7 +526,8 @@
             return true;
         }
 
-        if (deviceInfo.getDisplayName().equals(osdName)) {
+        if (deviceInfo.getDisplayName() != null
+            && deviceInfo.getDisplayName().equals(osdName)) {
             Slog.d(TAG, "Ignore incoming <Set Osd Name> having same osd name:" + message);
             return true;
         }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 63ba138..34fb641 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2071,7 +2071,7 @@
             // since the user never unlock the device manually. In this case, always
             // return a default metrics object. This is to distinguish this case from
             // the case where during boot user password is unknown yet (returning null here)
-            return new PasswordMetrics();
+            return new PasswordMetrics(CREDENTIAL_TYPE_NONE);
         }
         synchronized (this) {
             return mUserPasswordMetrics.get(userHandle);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 812ce32..09be474 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -797,6 +797,7 @@
                         writePolicyAL();
                     }
 
+                    enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true);
                     setRestrictBackgroundUL(mLoadedRestrictBackground);
                     updateRulesForGlobalChangeAL(false);
                     updateNotificationsNL();
@@ -3830,39 +3831,6 @@
     }
 
     /**
-     * Toggle the firewall standby chain and inform listeners if the uid rules have effectively
-     * changed.
-     */
-    @GuardedBy("mUidRulesFirstLock")
-    void updateRulesForAppIdleParoleUL() {
-        boolean paroled = mUsageStats.isAppIdleParoleOn();
-        boolean enableChain = !paroled;
-        enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
-
-        int ruleCount = mUidFirewallStandbyRules.size();
-        for (int i = 0; i < ruleCount; i++) {
-            int uid = mUidFirewallStandbyRules.keyAt(i);
-            int oldRules = mUidRules.get(uid);
-            if (enableChain) {
-                // Chain wasn't enabled before and the other power-related
-                // chains are whitelists, so we can clear the
-                // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
-                // the effective rules result in blocking network access.
-                oldRules &= MASK_METERED_NETWORKS;
-            } else {
-                // Skip if it had no restrictions to begin with
-                if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
-            }
-            final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
-            if (newUidRules == RULE_NONE) {
-                mUidRules.delete(uid);
-            } else {
-                mUidRules.put(uid, newUidRules);
-            }
-        }
-    }
-
-    /**
      * Update rules that might be changed by {@link #mRestrictBackground},
      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
      */
@@ -4317,7 +4285,7 @@
     private void updateRulesForPowerRestrictionsUL(int uid) {
         final int oldUidRules = mUidRules.get(uid, RULE_NONE);
 
-        final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
+        final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules);
 
         if (newUidRules == RULE_NONE) {
             mUidRules.delete(uid);
@@ -4331,30 +4299,28 @@
      *
      * @param uid the uid of the app to update rules for
      * @param oldUidRules the current rules for the uid, in order to determine if there's a change
-     * @param paroled whether to ignore idle state of apps and only look at other restrictions.
      *
      * @return the new computed rules for the uid
      */
-    private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
+    private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules) {
         if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
-                    "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
-                    + (paroled ? "P" : "-"));
+                    "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules);
         }
         try {
-            return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled);
+            return updateRulesForPowerRestrictionsULInner(uid, oldUidRules);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
         }
     }
 
-    private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) {
+    private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules) {
         if (!isUidValidForBlacklistRules(uid)) {
             if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
             return RULE_NONE;
         }
 
-        final boolean isIdle = !paroled && isUidIdle(uid);
+        final boolean isIdle = isUidIdle(uid);
         final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
         final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
 
@@ -4426,14 +4392,6 @@
             } catch (NameNotFoundException nnfe) {
             }
         }
-
-        @Override
-        public void onParoleStateChanged(boolean isParoleOn) {
-            synchronized (mUidRulesFirstLock) {
-                mLogger.paroleStateChanged(isParoleOn);
-                updateRulesForAppIdleParoleUL();
-            }
-        }
     }
 
     private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
@@ -4775,7 +4733,7 @@
     }
 
     /**
-     * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
+     * Calls {@link #setUidFirewallRulesUL(int, SparseIntArray)} and
      * {@link #enableFirewallChainUL(int, boolean)} synchronously.
      *
      * @param chain firewall chain.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ca979f8..cd3343b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5112,8 +5112,8 @@
         }
         if (contentViewSize >= mStripRemoteViewsSizeBytes) {
             mUsageStats.registerImageRemoved(pkg);
-            Slog.w(TAG,
-                    "Removed too large RemoteViews on pkg: " + pkg + " tag: " + tag + " id: " + id);
+            Slog.w(TAG, "Removed too large RemoteViews (" + contentViewSize + " bytes) on pkg: "
+                    + pkg + " tag: " + tag + " id: " + id);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 05b6168..c8179a7 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -131,7 +131,7 @@
 
     private static class FeatureConfigImpl implements FeatureConfig {
         private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled";
-        private volatile boolean mFeatureEnabled = true;
+        private volatile boolean mFeatureEnabled = false;
         private CompatConfig mCompatibility;
 
         private FeatureConfigImpl(PackageManagerService.Injector injector) {
@@ -141,12 +141,12 @@
         @Override
         public void onSystemReady() {
             mFeatureEnabled = DeviceConfig.getBoolean(
-                    NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, true);
+                    NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, false);
             DeviceConfig.addOnPropertiesChangedListener(
                     NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(),
                     properties -> {
                         synchronized (FeatureConfigImpl.this) {
-                            mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, true);
+                            mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, false);
                         }
                     });
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3f45b0b..5c65752 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -297,7 +297,7 @@
             // Critical; after this call the application should never have the permission
             mPackageManagerInt.writeSettings(false);
             final int appId = UserHandle.getAppId(uid);
-            killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+            mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
         }
         @Override
         public void onInstallPermissionRevoked() {
@@ -1902,7 +1902,7 @@
     private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
         synchronized (mLock) {
             mHasNoDelayedPermBackup.delete(user.getIdentifier());
-            mPermissionControllerManager.restoreRuntimePermissionBackup(backup, user);
+            mPermissionControllerManager.stageAndApplyRuntimePermissionsBackup(backup, user);
         }
     }
 
@@ -1923,7 +1923,7 @@
                 return;
             }
 
-            mPermissionControllerManager.restoreDelayedRuntimePermissionBackup(packageName, user,
+            mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName, user,
                     mContext.getMainExecutor(), (hasMoreBackup) -> {
                         if (hasMoreBackup) {
                             return;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 3cdb59b..3663f46 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1228,6 +1228,7 @@
                         saveSettingsLocked(mWallpaper.userId);
                     }
                     FgThread.getHandler().removeCallbacks(mResetRunnable);
+                    mContext.getMainThreadHandler().removeCallbacks(this::tryToRebind);
                 }
             }
         }
@@ -1270,6 +1271,34 @@
             }
         }
 
+        private void tryToRebind() {
+            synchronized (mLock) {
+                if (mWallpaper.wallpaperUpdating) {
+                    return;
+                }
+                final ComponentName wpService = mWallpaper.wallpaperComponent;
+                // The broadcast of package update could be delayed after service disconnected. Try
+                // to re-bind the service for 10 seconds.
+                if (bindWallpaperComponentLocked(
+                        wpService, true, false, mWallpaper, null)) {
+                    mWallpaper.connection.scheduleTimeoutLocked();
+                } else if (SystemClock.uptimeMillis() - mWallpaper.lastDiedTime
+                        < WALLPAPER_RECONNECT_TIMEOUT_MS) {
+                    // Bind fail without timeout, schedule rebind
+                    Slog.w(TAG, "Rebind fail! Try again later");
+                    mContext.getMainThreadHandler().postDelayed(this::tryToRebind, 1000);
+                } else {
+                    // Timeout
+                    Slog.w(TAG, "Reverting to built-in wallpaper!");
+                    clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
+                    final String flattened = wpService.flattenToString();
+                    EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
+                            flattened.substring(0, Math.min(flattened.length(),
+                                    MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
+                }
+            }
+        }
+
         private void processDisconnect(final ServiceConnection connection) {
             synchronized (mLock) {
                 // The wallpaper disappeared.  If this isn't a system-default one, track
@@ -1293,20 +1322,8 @@
                             clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
                         } else {
                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
-
-                            clearWallpaperComponentLocked(mWallpaper);
-                            if (bindWallpaperComponentLocked(
-                                    wpService, false, false, mWallpaper, null)) {
-                                mWallpaper.connection.scheduleTimeoutLocked();
-                            } else {
-                                Slog.w(TAG, "Reverting to built-in wallpaper!");
-                                clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
-                            }
+                            tryToRebind();
                         }
-                        final String flattened = wpService.flattenToString();
-                        EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
-                                flattened.substring(0, Math.min(flattened.length(),
-                                        MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
                     }
                 } else {
                     if (DEBUG_LIVE) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76a551f..fb4de01 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2005,10 +2005,6 @@
         if (stopped) {
             clearOptionsLocked();
         }
-
-        if (mAtmService != null) {
-            mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
-        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 7753f57..ca74196 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1796,6 +1796,7 @@
             tr.removeTaskActivitiesLocked(reason);
             cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
             mService.getLockTaskController().clearLockedTask(tr);
+            mService.getTaskChangeNotificationController().notifyTaskStackChanged();
             if (tr.isPersistable) {
                 mService.notifyTaskPersisterLocked(null, true);
             }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1a80006..c505454 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1834,7 +1834,9 @@
      */
     private void complyActivityFlags(TaskRecord targetTask, ActivityRecord reusedActivity) {
         ActivityRecord targetTaskTop = targetTask.getTopActivity();
-        if (reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+        final boolean resetTask =
+                reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0;
+        if (resetTask) {
             targetTaskTop = mTargetStack.resetTaskIfNeededLocked(targetTaskTop, mStartActivity);
         }
 
@@ -1926,7 +1928,7 @@
             } else if (reusedActivity == null) {
                 mAddingToTask = true;
             }
-        } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+        } else if (!resetTask) {
             // In this case an activity is being launched in to an existing task, without
             // resetting that task. This is typically the situation of launching an activity
             // from a notification or shortcut. We want to place the new activity on top of the
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f0717ca..2657826 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -120,12 +120,12 @@
 
     // TODO: Remove after unification.
     @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
+    public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
         // Forward configuration changes in cases
         // - children won't get it from TaskRecord
         // - it's a pinned task
-        onConfigurationChanged(newParentConfig,
-                (mTaskRecord == null) || inPinnedWindowingMode() /*forwardToChildren*/);
+        forwardToChildren &= (mTaskRecord == null) || inPinnedWindowingMode();
+        super.onConfigurationChanged(newParentConfig, forwardToChildren);
     }
 
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0ae205a..6f643c9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -129,6 +129,7 @@
 import android.app.admin.DeviceStateCache;
 import android.app.admin.NetworkEvent;
 import android.app.admin.PasswordMetrics;
+import android.app.admin.PasswordPolicy;
 import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.app.admin.StartInstallingUpdateCallback;
@@ -255,6 +256,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.SystemServerInitThreadPool;
@@ -989,19 +991,8 @@
         static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
         int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
 
-        static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
-        static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
-        static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
-        static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
-        static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
-        static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
-        static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
         @NonNull
-        PasswordMetrics minimumPasswordMetrics = new PasswordMetrics(
-                PASSWORD_QUALITY_UNSPECIFIED, DEF_MINIMUM_PASSWORD_LENGTH,
-                DEF_MINIMUM_PASSWORD_LETTERS, DEF_MINIMUM_PASSWORD_UPPER_CASE,
-                DEF_MINIMUM_PASSWORD_LOWER_CASE, DEF_MINIMUM_PASSWORD_NUMERIC,
-                DEF_MINIMUM_PASSWORD_SYMBOLS, DEF_MINIMUM_PASSWORD_NON_LETTER);
+        PasswordPolicy mPasswordPolicy = new PasswordPolicy();
 
         static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
         long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
@@ -1136,36 +1127,36 @@
             out.startTag(null, TAG_POLICIES);
             info.writePoliciesToXml(out);
             out.endTag(null, TAG_POLICIES);
-            if (minimumPasswordMetrics.quality != PASSWORD_QUALITY_UNSPECIFIED) {
+            if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) {
                 writeAttributeValueToXml(
-                        out, TAG_PASSWORD_QUALITY, minimumPasswordMetrics.quality);
-                if (minimumPasswordMetrics.length != DEF_MINIMUM_PASSWORD_LENGTH) {
+                        out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality);
+                if (mPasswordPolicy.length != PasswordPolicy.DEF_MINIMUM_LENGTH) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_LENGTH, minimumPasswordMetrics.length);
+                            out, TAG_MIN_PASSWORD_LENGTH, mPasswordPolicy.length);
                 }
-                if (minimumPasswordMetrics.upperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
+                if (mPasswordPolicy.upperCase != PasswordPolicy.DEF_MINIMUM_UPPER_CASE) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_UPPERCASE, minimumPasswordMetrics.upperCase);
+                            out, TAG_MIN_PASSWORD_UPPERCASE, mPasswordPolicy.upperCase);
                 }
-                if (minimumPasswordMetrics.lowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
+                if (mPasswordPolicy.lowerCase != PasswordPolicy.DEF_MINIMUM_LOWER_CASE) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_LOWERCASE, minimumPasswordMetrics.lowerCase);
+                            out, TAG_MIN_PASSWORD_LOWERCASE, mPasswordPolicy.lowerCase);
                 }
-                if (minimumPasswordMetrics.letters != DEF_MINIMUM_PASSWORD_LETTERS) {
+                if (mPasswordPolicy.letters != PasswordPolicy.DEF_MINIMUM_LETTERS) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_LETTERS, minimumPasswordMetrics.letters);
+                            out, TAG_MIN_PASSWORD_LETTERS, mPasswordPolicy.letters);
                 }
-                if (minimumPasswordMetrics.numeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
+                if (mPasswordPolicy.numeric != PasswordPolicy.DEF_MINIMUM_NUMERIC) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_NUMERIC, minimumPasswordMetrics.numeric);
+                            out, TAG_MIN_PASSWORD_NUMERIC, mPasswordPolicy.numeric);
                 }
-                if (minimumPasswordMetrics.symbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
+                if (mPasswordPolicy.symbols != PasswordPolicy.DEF_MINIMUM_SYMBOLS) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_SYMBOLS, minimumPasswordMetrics.symbols);
+                            out, TAG_MIN_PASSWORD_SYMBOLS, mPasswordPolicy.symbols);
                 }
-                if (minimumPasswordMetrics.nonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
+                if (mPasswordPolicy.nonLetter > PasswordPolicy.DEF_MINIMUM_NON_LETTER) {
                     writeAttributeValueToXml(
-                            out, TAG_MIN_PASSWORD_NONLETTER, minimumPasswordMetrics.nonLetter);
+                            out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter);
                 }
             }
             if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
@@ -1404,31 +1395,31 @@
                         info.readPoliciesFromXml(parser);
                     }
                 } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
-                    minimumPasswordMetrics.quality = Integer.parseInt(
+                    mPasswordPolicy.quality = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
-                    minimumPasswordMetrics.length = Integer.parseInt(
+                    mPasswordPolicy.length = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
                     passwordHistoryLength = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
-                    minimumPasswordMetrics.upperCase = Integer.parseInt(
+                    mPasswordPolicy.upperCase = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
-                    minimumPasswordMetrics.lowerCase = Integer.parseInt(
+                    mPasswordPolicy.lowerCase = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
-                    minimumPasswordMetrics.letters = Integer.parseInt(
+                    mPasswordPolicy.letters = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
-                    minimumPasswordMetrics.numeric = Integer.parseInt(
+                    mPasswordPolicy.numeric = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
-                    minimumPasswordMetrics.symbols = Integer.parseInt(
+                    mPasswordPolicy.symbols = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
-                    minimumPasswordMetrics.nonLetter = Integer.parseInt(
+                    mPasswordPolicy.nonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 }else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                     maximumTimeToUnlock = Long.parseLong(
@@ -1689,23 +1680,23 @@
                 pw.decreaseIndent();
             }
             pw.print("passwordQuality=0x");
-                    pw.println(Integer.toHexString(minimumPasswordMetrics.quality));
+                    pw.println(Integer.toHexString(mPasswordPolicy.quality));
             pw.print("minimumPasswordLength=");
-                    pw.println(minimumPasswordMetrics.length);
+                    pw.println(mPasswordPolicy.length);
             pw.print("passwordHistoryLength=");
                     pw.println(passwordHistoryLength);
             pw.print("minimumPasswordUpperCase=");
-                    pw.println(minimumPasswordMetrics.upperCase);
+                    pw.println(mPasswordPolicy.upperCase);
             pw.print("minimumPasswordLowerCase=");
-                    pw.println(minimumPasswordMetrics.lowerCase);
+                    pw.println(mPasswordPolicy.lowerCase);
             pw.print("minimumPasswordLetters=");
-                    pw.println(minimumPasswordMetrics.letters);
+                    pw.println(mPasswordPolicy.letters);
             pw.print("minimumPasswordNumeric=");
-                    pw.println(minimumPasswordMetrics.numeric);
+                    pw.println(mPasswordPolicy.numeric);
             pw.print("minimumPasswordSymbols=");
-                    pw.println(minimumPasswordMetrics.symbols);
+                    pw.println(mPasswordPolicy.symbols);
             pw.print("minimumPasswordNonLetter=");
-                    pw.println(minimumPasswordMetrics.nonLetter);
+                    pw.println(mPasswordPolicy.nonLetter);
             pw.print("maximumTimeToUnlock=");
                     pw.println(maximumTimeToUnlock);
             pw.print("strongAuthUnlockTimeout=");
@@ -4162,15 +4153,15 @@
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
-                final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-                if (metrics.quality != quality) {
-                    metrics.quality = quality;
+                final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+                if (passwordPolicy.quality != quality) {
+                    passwordPolicy.quality = quality;
                     resetInactivePasswordRequirementsIfRPlus(userId, ap);
                     updatePasswordValidityCheckpointLocked(userId, parent);
                     updatePasswordQualityCacheForUserGroup(userId);
                     saveSettingsLocked(userId);
                 }
-                maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+                maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
@@ -4199,17 +4190,17 @@
      */
     private void resetInactivePasswordRequirementsIfRPlus(int userId, ActiveAdmin admin) {
         if (passwordQualityInvocationOrderCheckEnabled(admin.info.getPackageName(), userId)) {
-            final PasswordMetrics metrics = admin.minimumPasswordMetrics;
-            if (metrics.quality < PASSWORD_QUALITY_NUMERIC) {
-                metrics.length = ActiveAdmin.DEF_MINIMUM_PASSWORD_LENGTH;
+            final PasswordPolicy policy = admin.mPasswordPolicy;
+            if (policy.quality < PASSWORD_QUALITY_NUMERIC) {
+                policy.length = PasswordPolicy.DEF_MINIMUM_LENGTH;
             }
-            if (metrics.quality < PASSWORD_QUALITY_COMPLEX) {
-                metrics.letters = ActiveAdmin.DEF_MINIMUM_PASSWORD_LETTERS;
-                metrics.upperCase = ActiveAdmin.DEF_MINIMUM_PASSWORD_UPPER_CASE;
-                metrics.lowerCase = ActiveAdmin.DEF_MINIMUM_PASSWORD_LOWER_CASE;
-                metrics.numeric = ActiveAdmin.DEF_MINIMUM_PASSWORD_NUMERIC;
-                metrics.symbols = ActiveAdmin.DEF_MINIMUM_PASSWORD_SYMBOLS;
-                metrics.nonLetter = ActiveAdmin.DEF_MINIMUM_PASSWORD_NON_LETTER;
+            if (policy.quality < PASSWORD_QUALITY_COMPLEX) {
+                policy.letters = PasswordPolicy.DEF_MINIMUM_LETTERS;
+                policy.upperCase = PasswordPolicy.DEF_MINIMUM_UPPER_CASE;
+                policy.lowerCase = PasswordPolicy.DEF_MINIMUM_LOWER_CASE;
+                policy.numeric = PasswordPolicy.DEF_MINIMUM_NUMERIC;
+                policy.symbols = PasswordPolicy.DEF_MINIMUM_SYMBOLS;
+                policy.nonLetter = PasswordPolicy.DEF_MINIMUM_NON_LETTER;
             }
         }
     }
@@ -4274,7 +4265,7 @@
 
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
-                return admin != null ? admin.minimumPasswordMetrics.quality : mode;
+                return admin != null ? admin.mPasswordPolicy.quality : mode;
             }
 
             // Return the strictest policy across all participating admins.
@@ -4283,8 +4274,8 @@
             final int N = admins.size();
             for (int i = 0; i < N; i++) {
                 ActiveAdmin admin = admins.get(i);
-                if (mode < admin.minimumPasswordMetrics.quality) {
-                    mode = admin.minimumPasswordMetrics.quality;
+                if (mode < admin.mPasswordPolicy.quality) {
+                    mode = admin.mPasswordPolicy.quality;
                 }
             }
             return mode;
@@ -4344,14 +4335,14 @@
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
             ensureMinimumQuality(userId, ap, PASSWORD_QUALITY_NUMERIC, "setPasswordMinimumLength");
-            if (metrics.length != length) {
-                metrics.length = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.length != length) {
+                passwordPolicy.length = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_LENGTH)
@@ -4362,7 +4353,7 @@
 
     private void ensureMinimumQuality(
             int userId, ActiveAdmin admin, int minimumQuality, String operation) {
-        if (admin.minimumPasswordMetrics.quality < minimumQuality
+        if (admin.mPasswordPolicy.quality < minimumQuality
                 && passwordQualityInvocationOrderCheckEnabled(admin.info.getPackageName(),
                 userId)) {
             throw new IllegalStateException(String.format(
@@ -4373,7 +4364,7 @@
     @Override
     public int getPasswordMinimumLength(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.length, PASSWORD_QUALITY_NUMERIC);
+                admin -> admin.mPasswordPolicy.length, PASSWORD_QUALITY_NUMERIC);
     }
 
     @Override
@@ -4602,13 +4593,13 @@
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             ensureMinimumQuality(
                     userId, ap, PASSWORD_QUALITY_COMPLEX, "setPasswordMinimumUpperCase");
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-            if (metrics.upperCase != length) {
-                metrics.upperCase = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.upperCase != length) {
+                passwordPolicy.upperCase = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_UPPER_CASE)
@@ -4620,7 +4611,7 @@
     @Override
     public int getPasswordMinimumUpperCase(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.upperCase, PASSWORD_QUALITY_COMPLEX);
+                admin -> admin.mPasswordPolicy.upperCase, PASSWORD_QUALITY_COMPLEX);
     }
 
     @Override
@@ -4632,13 +4623,13 @@
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             ensureMinimumQuality(
                     userId, ap, PASSWORD_QUALITY_COMPLEX, "setPasswordMinimumLowerCase");
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-            if (metrics.lowerCase != length) {
-                metrics.lowerCase = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.lowerCase != length) {
+                passwordPolicy.lowerCase = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_LOWER_CASE)
@@ -4650,7 +4641,7 @@
     @Override
     public int getPasswordMinimumLowerCase(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.lowerCase, PASSWORD_QUALITY_COMPLEX);
+                admin -> admin.mPasswordPolicy.lowerCase, PASSWORD_QUALITY_COMPLEX);
     }
 
     @Override
@@ -4664,13 +4655,13 @@
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             ensureMinimumQuality(userId, ap, PASSWORD_QUALITY_COMPLEX, "setPasswordMinimumLetters");
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-            if (metrics.letters != length) {
-                metrics.letters = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.letters != length) {
+                passwordPolicy.letters = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_LETTERS)
@@ -4682,7 +4673,7 @@
     @Override
     public int getPasswordMinimumLetters(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.letters, PASSWORD_QUALITY_COMPLEX);
+                admin -> admin.mPasswordPolicy.letters, PASSWORD_QUALITY_COMPLEX);
     }
 
     @Override
@@ -4696,13 +4687,13 @@
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             ensureMinimumQuality(userId, ap, PASSWORD_QUALITY_COMPLEX, "setPasswordMinimumNumeric");
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-            if (metrics.numeric != length) {
-                metrics.numeric = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.numeric != length) {
+                passwordPolicy.numeric = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_NUMERIC)
@@ -4714,7 +4705,7 @@
     @Override
     public int getPasswordMinimumNumeric(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.numeric, PASSWORD_QUALITY_COMPLEX);
+                admin -> admin.mPasswordPolicy.numeric, PASSWORD_QUALITY_COMPLEX);
     }
 
     @Override
@@ -4728,13 +4719,13 @@
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             ensureMinimumQuality(userId, ap, PASSWORD_QUALITY_COMPLEX, "setPasswordMinimumSymbols");
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-            if (metrics.symbols != length) {
-                ap.minimumPasswordMetrics.symbols = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.symbols != length) {
+                ap.mPasswordPolicy.symbols = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_SYMBOLS)
@@ -4746,7 +4737,7 @@
     @Override
     public int getPasswordMinimumSymbols(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.symbols, PASSWORD_QUALITY_COMPLEX);
+                admin -> admin.mPasswordPolicy.symbols, PASSWORD_QUALITY_COMPLEX);
     }
 
     @Override
@@ -4761,13 +4752,13 @@
                     who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             ensureMinimumQuality(
                     userId, ap, PASSWORD_QUALITY_COMPLEX, "setPasswordMinimumNonLetter");
-            final PasswordMetrics metrics = ap.minimumPasswordMetrics;
-            if (metrics.nonLetter != length) {
-                ap.minimumPasswordMetrics.nonLetter = length;
+            final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
+            if (passwordPolicy.nonLetter != length) {
+                ap.mPasswordPolicy.nonLetter = length;
                 updatePasswordValidityCheckpointLocked(userId, parent);
                 saveSettingsLocked(userId);
             }
-            maybeLogPasswordComplexitySet(who, userId, parent, metrics);
+            maybeLogPasswordComplexitySet(who, userId, parent, passwordPolicy);
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_NON_LETTER)
@@ -4779,7 +4770,7 @@
     @Override
     public int getPasswordMinimumNonLetter(ComponentName who, int userHandle, boolean parent) {
         return getStrictestPasswordRequirement(who, userHandle, parent,
-                admin -> admin.minimumPasswordMetrics.nonLetter, PASSWORD_QUALITY_COMPLEX);
+                admin -> admin.mPasswordPolicy.nonLetter, PASSWORD_QUALITY_COMPLEX);
     }
 
     /**
@@ -4815,6 +4806,33 @@
         }
     }
 
+    /**
+     * Calculates strictest (maximum) value for a given password property enforced by admin[s].
+     */
+    @Override
+    public PasswordMetrics getPasswordMinimumMetrics(@UserIdInt int userHandle) {
+        return getPasswordMinimumMetrics(userHandle, false /* parent */);
+    }
+
+    /**
+     * Calculates strictest (maximum) value for a given password property enforced by admin[s].
+     */
+    private PasswordMetrics getPasswordMinimumMetrics(@UserIdInt int userHandle, boolean parent) {
+        if (!mHasFeature) {
+            new PasswordMetrics(LockPatternUtils.CREDENTIAL_TYPE_NONE);
+        }
+        enforceFullCrossUsersPermission(userHandle);
+        ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>();
+        synchronized (getLockObject()) {
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            for (ActiveAdmin admin : admins) {
+                adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+            }
+        }
+        return PasswordMetrics.merge(adminMetrics);
+    }
+
     @Override
     public boolean isActivePasswordSufficient(int userHandle, boolean parent) {
         if (!mHasFeature) {
@@ -4830,8 +4848,9 @@
             int credentialOwner = getCredentialOwner(userHandle, parent);
             DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
             PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
-            return isActivePasswordSufficientForUserLocked(
+            boolean activePasswordSufficientForUserLocked = isActivePasswordSufficientForUserLocked(
                     policy.mPasswordValidAtLastCheckpoint, metrics, userHandle, parent);
+            return activePasswordSufficientForUserLocked;
         }
     }
 
@@ -4894,25 +4913,11 @@
      */
     private boolean isPasswordSufficientForUserWithoutCheckpointLocked(
             @NonNull PasswordMetrics metrics, @UserIdInt int userId, boolean parent) {
-        final int requiredQuality = getPasswordQuality(null, userId, parent);
-
-        if (requiredQuality >= PASSWORD_QUALITY_NUMERIC
-                && metrics.length < getPasswordMinimumLength(null, userId, parent)) {
-            return false;
-        }
-
-        // PASSWORD_QUALITY_COMPLEX doesn't represent actual password quality, it means that number
-        // of characters of each class should be checked instead of quality itself.
-        if (requiredQuality == PASSWORD_QUALITY_COMPLEX) {
-            return metrics.upperCase >= getPasswordMinimumUpperCase(null, userId, parent)
-                    && metrics.lowerCase >= getPasswordMinimumLowerCase(null, userId, parent)
-                    && metrics.letters >= getPasswordMinimumLetters(null, userId, parent)
-                    && metrics.numeric >= getPasswordMinimumNumeric(null, userId, parent)
-                    && metrics.symbols >= getPasswordMinimumSymbols(null, userId, parent)
-                    && metrics.nonLetter >= getPasswordMinimumNonLetter(null, userId, parent);
-        } else {
-            return metrics.quality >= requiredQuality;
-        }
+        PasswordMetrics minMetrics = getPasswordMinimumMetrics(userId, parent);
+        final List<PasswordValidationError> passwordValidationErrors =
+                PasswordMetrics.validatePasswordMetrics(
+                        minMetrics, PASSWORD_COMPLEXITY_NONE, false, metrics);
+        return passwordValidationErrors.isEmpty();
     }
 
     @Override
@@ -5170,77 +5175,17 @@
 
     private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token,
             int flags, int callingUid, int userHandle) {
-        int quality;
         synchronized (getLockObject()) {
-            quality = getPasswordQuality(null, userHandle, /* parent */ false);
-            if (quality == PASSWORD_QUALITY_MANAGED) {
-                quality = PASSWORD_QUALITY_UNSPECIFIED;
-            }
             // TODO(b/120484642): remove getBytes() below
-            final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes());
-            final int realQuality = metrics.quality;
-            if (realQuality < quality && quality != PASSWORD_QUALITY_COMPLEX) {
-                Slog.w(LOG_TAG, "resetPassword: password quality 0x"
-                        + Integer.toHexString(realQuality)
-                        + " does not meet required quality 0x"
-                        + Integer.toHexString(quality));
+            final PasswordMetrics minMetrics = getPasswordMinimumMetrics(userHandle);
+            final List<PasswordValidationError> validationErrors =
+                    PasswordMetrics.validatePassword(
+                            minMetrics, PASSWORD_COMPLEXITY_NONE, false, password.getBytes());
+            if (!validationErrors.isEmpty()) {
+                Log.w(LOG_TAG, "Failed to reset password due to constraint violation: "
+                        + validationErrors.get(0));
                 return false;
             }
-            quality = Math.max(realQuality, quality);
-            int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
-            if (password.length() < length) {
-                Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
-                        + " does not meet required length " + length);
-                return false;
-            }
-            if (quality == PASSWORD_QUALITY_COMPLEX) {
-                int neededLetters = getPasswordMinimumLetters(null, userHandle, /* parent */ false);
-                if(metrics.letters < neededLetters) {
-                    Slog.w(LOG_TAG, "resetPassword: number of letters " + metrics.letters
-                            + " does not meet required number of letters " + neededLetters);
-                    return false;
-                }
-                int neededNumeric = getPasswordMinimumNumeric(null, userHandle, /* parent */ false);
-                if (metrics.numeric < neededNumeric) {
-                    Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + metrics.numeric
-                            + " does not meet required number of numerical digits "
-                            + neededNumeric);
-                    return false;
-                }
-                int neededLowerCase = getPasswordMinimumLowerCase(
-                        null, userHandle, /* parent */ false);
-                if (metrics.lowerCase < neededLowerCase) {
-                    Slog.w(LOG_TAG, "resetPassword: number of lowercase letters "
-                            + metrics.lowerCase
-                            + " does not meet required number of lowercase letters "
-                            + neededLowerCase);
-                    return false;
-                }
-                int neededUpperCase = getPasswordMinimumUpperCase(
-                        null, userHandle, /* parent */ false);
-                if (metrics.upperCase < neededUpperCase) {
-                    Slog.w(LOG_TAG, "resetPassword: number of uppercase letters "
-                            + metrics.upperCase
-                            + " does not meet required number of uppercase letters "
-                            + neededUpperCase);
-                    return false;
-                }
-                int neededSymbols = getPasswordMinimumSymbols(null, userHandle, /* parent */ false);
-                if (metrics.symbols < neededSymbols) {
-                    Slog.w(LOG_TAG, "resetPassword: number of special symbols " + metrics.symbols
-                            + " does not meet required number of special symbols " + neededSymbols);
-                    return false;
-                }
-                int neededNonLetter = getPasswordMinimumNonLetter(
-                        null, userHandle, /* parent */ false);
-                if (metrics.nonLetter < neededNonLetter) {
-                    Slog.w(LOG_TAG, "resetPassword: number of non-letter characters "
-                            + metrics.nonLetter
-                            + " does not meet required number of non-letter characters "
-                            + neededNonLetter);
-                    return false;
-                }
-            }
         }
 
         DevicePolicyData policy = getUserData(userHandle);
@@ -11604,10 +11549,10 @@
 
     /**
      * Returns true if specified admin is allowed to limit passwords and has a
-     * {@code minimumPasswordMetrics.quality} of at least {@code minPasswordQuality}
+     * {@code mPasswordPolicy.quality} of at least {@code minPasswordQuality}
      */
     private static boolean isLimitPasswordAllowed(ActiveAdmin admin, int minPasswordQuality) {
-        if (admin.minimumPasswordMetrics.quality < minPasswordQuality) {
+        if (admin.mPasswordPolicy.quality < minPasswordQuality) {
             return false;
         }
         return admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
@@ -14226,13 +14171,13 @@
     }
 
     private void maybeLogPasswordComplexitySet(ComponentName who, int userId, boolean parent,
-            PasswordMetrics metrics) {
+            PasswordPolicy passwordPolicy) {
         if (SecurityLog.isLoggingEnabled()) {
             final int affectedUserId = parent ? getProfileParentId(userId) : userId;
             SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_COMPLEXITY_SET, who.getPackageName(),
-                    userId, affectedUserId, metrics.length, metrics.quality, metrics.letters,
-                    metrics.nonLetter, metrics.numeric, metrics.upperCase, metrics.lowerCase,
-                    metrics.symbols);
+                    userId, affectedUserId, passwordPolicy.length, passwordPolicy.quality,
+                    passwordPolicy.letters, passwordPolicy.nonLetter, passwordPolicy.numeric,
+                    passwordPolicy.upperCase, passwordPolicy.lowerCase, passwordPolicy.symbols);
         }
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 6e8b86a..7b7b8e6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -34,7 +34,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.AlarmManagerService.ACTIVE_INDEX;
 import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
-import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_PAROLE_CHANGED;
+import static com.android.server.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
@@ -53,6 +53,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.atLeastOnce;
@@ -68,6 +69,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -107,6 +109,7 @@
     private long mAppStandbyWindow;
     private AlarmManagerService mService;
     private UsageStatsManagerInternal.AppIdleStateChangeListener mAppStandbyListener;
+    private AlarmManagerService.ChargingReceiver mChargingReceiver;
     @Mock
     private ContentResolver mMockResolver;
     @Mock
@@ -290,6 +293,13 @@
                 ArgumentCaptor.forClass(UsageStatsManagerInternal.AppIdleStateChangeListener.class);
         verify(mUsageStatsManagerInternal).addAppIdleStateChangeListener(captor.capture());
         mAppStandbyListener = captor.getValue();
+
+        ArgumentCaptor<AlarmManagerService.ChargingReceiver> chargingReceiverCaptor =
+                ArgumentCaptor.forClass(AlarmManagerService.ChargingReceiver.class);
+        verify(mMockContext).registerReceiver(chargingReceiverCaptor.capture(),
+                argThat((filter) -> filter.hasAction(BatteryManager.ACTION_CHARGING)
+                        && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
+        mChargingReceiver = chargingReceiverCaptor.getValue();
     }
 
     private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
@@ -724,17 +734,19 @@
     }
 
     private void assertAndHandleParoleChanged(boolean parole) {
-        mAppStandbyListener.onParoleStateChanged(parole);
+        mChargingReceiver.onReceive(mMockContext,
+                new Intent(parole ? BatteryManager.ACTION_CHARGING
+                        : BatteryManager.ACTION_DISCHARGING));
         final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
         final Message lastMessage = messageCaptor.getValue();
         assertEquals("Unexpected message send to handler", lastMessage.what,
-                APP_STANDBY_PAROLE_CHANGED);
+                CHARGING_STATUS_CHANGED);
         mService.mHandler.handleMessage(lastMessage);
     }
 
     @Test
-    public void testParole() throws Exception {
+    public void testCharging() throws Exception {
         setQuotasEnabled(true);
         final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
         when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index d0158e0..247a358 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -64,6 +64,9 @@
 import android.util.ArraySet;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
 import com.android.server.AppStateTracker.Listener;
@@ -85,14 +88,10 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 /**
  * Tests for {@link AppStateTracker}
  *
- * Run with:
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+ * Run with: atest com.android.server.AppStateTrackerTest
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index 9180054..d70e164 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -207,14 +207,14 @@
     }
 
     @Test
-    public void serviceDisconnected_removeServiceAndAddToBinding() {
+    public void serviceDisconnected_removeServiceAndAddToCrashed() {
         when(mMockConnection.getComponentName()).thenReturn(COMPONENT_NAME);
         mUserState.addServiceLocked(mMockConnection);
 
         mUserState.serviceDisconnectedLocked(mMockConnection);
 
         assertFalse(mUserState.getBoundServicesLocked().contains(mMockConnection));
-        assertTrue(mUserState.getBindingServicesLocked().contains(COMPONENT_NAME));
+        assertTrue(mUserState.getCrashedServicesLocked().contains(COMPONENT_NAME));
     }
 
     @Test
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 c3ef832..aeccfc5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -25,10 +25,12 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
+import static android.app.admin.PasswordMetrics.computeForPassword;
 import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
 import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
 import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
 
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
 import static com.android.server.testutils.TestUtils.assertExpectException;
 
@@ -4295,11 +4297,7 @@
 
         reset(mContext.spiedContext);
 
-        PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics(
-                DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
-                8, 2,
-                6, 1,
-                0, 1);
+        PasswordMetrics passwordMetricsNoSymbols = computeForPassword("abcdXYZ5".getBytes());
 
         setActivePasswordState(passwordMetricsNoSymbols);
         assertTrue(dpm.isActivePasswordSufficient());
@@ -4326,11 +4324,7 @@
         reset(mContext.spiedContext);
         assertFalse(dpm.isActivePasswordSufficient());
 
-        PasswordMetrics passwordMetricsWithSymbols = new PasswordMetrics(
-                DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
-                7, 2,
-                5, 1,
-                1, 2);
+        PasswordMetrics passwordMetricsWithSymbols = computeForPassword("abcd.XY5".getBytes());
 
         setActivePasswordState(passwordMetricsWithSymbols);
         assertTrue(dpm.isActivePasswordSufficient());
@@ -4347,7 +4341,7 @@
         final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
         // When there is no lockscreen, user password metrics is always empty.
         when(getServices().lockSettingsInternal.getUserPasswordMetrics(userHandle))
-                .thenReturn(new PasswordMetrics());
+                .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE));
 
         // If no password requirements are set, isActivePasswordSufficient should succeed.
         assertTrue(dpm.isActivePasswordSufficient());
@@ -5314,7 +5308,7 @@
                 .thenReturn(DpmMockContext.CALLER_USER_HANDLE);
         when(getServices().lockSettingsInternal
                 .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE))
-                .thenReturn(PasswordMetrics.computeForPassword("asdf".getBytes()));
+                .thenReturn(computeForPassword("asdf".getBytes()));
 
         assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity());
     }
@@ -5331,10 +5325,10 @@
 
         when(getServices().lockSettingsInternal
                 .getUserPasswordMetrics(DpmMockContext.CALLER_USER_HANDLE))
-                .thenReturn(PasswordMetrics.computeForPassword("asdf".getBytes()));
+                .thenReturn(computeForPassword("asdf".getBytes()));
         when(getServices().lockSettingsInternal
                 .getUserPasswordMetrics(parentUser.id))
-                .thenReturn(PasswordMetrics.computeForPassword("parentUser".getBytes()));
+                .thenReturn(computeForPassword("parentUser".getBytes()));
 
         assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity());
     }
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index fe7a376..25b41db 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -29,7 +29,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.support.test.uiautomator.UiDevice;
 import android.text.TextUtils;
 import android.util.Log;
@@ -88,17 +87,11 @@
 
     private static final int REPEAT_TEST_COUNT = 5;
 
-    private static final String KEY_PAROLE_DURATION = "parole_duration";
-    private static final String DESIRED_PAROLE_DURATION = "0";
-
     private static Context mContext;
     private static UiDevice mUiDevice;
     private static int mTestPkgUid;
     private static BatteryManager mBatteryManager;
 
-    private static boolean mAppIdleConstsUpdated;
-    private static String mOriginalAppIdleConsts;
-
     private static ServiceConnection mServiceConnection;
     private static ICmdReceiverService mCmdReceiverService;
 
@@ -107,7 +100,6 @@
         mContext = InstrumentationRegistry.getContext();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
-        setDesiredParoleDuration();
         mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
         mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
@@ -119,10 +111,6 @@
     @AfterClass
     public static void tearDownOnce() throws Exception {
         batteryReset();
-        if (mAppIdleConstsUpdated) {
-            Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.APP_IDLE_CONSTANTS, mOriginalAppIdleConsts);
-        }
         unbindService();
     }
 
@@ -160,27 +148,6 @@
         }
     }
 
-    private static void setDesiredParoleDuration() {
-        mOriginalAppIdleConsts = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.APP_IDLE_CONSTANTS);
-        String newAppIdleConstants;
-        final String newConstant = KEY_PAROLE_DURATION + "=" + DESIRED_PAROLE_DURATION;
-        if (mOriginalAppIdleConsts == null || "null".equals(mOriginalAppIdleConsts)) {
-            // app_idle_constants is initially empty, so just assign the desired value.
-            newAppIdleConstants = newConstant;
-        } else if (mOriginalAppIdleConsts.contains(KEY_PAROLE_DURATION)) {
-            // app_idle_constants contains parole_duration, so replace it with the desired value.
-            newAppIdleConstants = mOriginalAppIdleConsts.replaceAll(
-                    KEY_PAROLE_DURATION + "=\\d+", newConstant);
-        } else {
-            // app_idle_constants didn't have parole_duration, so append the desired value.
-            newAppIdleConstants = mOriginalAppIdleConsts + "," + newConstant;
-        }
-        Settings.Global.putString(mContext.getContentResolver(),
-                Settings.Global.APP_IDLE_CONSTANTS, newAppIdleConstants);
-        mAppIdleConstsUpdated = true;
-    }
-
     @Test
     public void testStartActivity_batterySaver() throws Exception {
         setBatterySaverMode(true);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 4ffcf8f..12ba219 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -47,7 +47,6 @@
 
 import android.app.usage.AppStandbyInfo;
 import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -77,7 +76,6 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -108,8 +106,6 @@
     private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
     private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
     private static final long RARE_THRESHOLD = 48 * HOUR_MS;
-    // Short STABLE_CHARGING_THRESHOLD for testing purposes
-    private static final long STABLE_CHARGING_THRESHOLD = 2000;
 
     /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
     private static boolean isPackageInstalled = true;
@@ -132,7 +128,6 @@
     static class MyInjector extends AppStandbyController.Injector {
         long mElapsedRealtime;
         boolean mIsAppIdleEnabled = true;
-        boolean mIsCharging;
         List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
         boolean mDisplayOn;
         DisplayManager.DisplayListener mDisplayListener;
@@ -167,11 +162,6 @@
         }
 
         @Override
-        boolean isCharging() {
-            return mIsCharging;
-        }
-
-        @Override
         boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
             return mPowerSaveWhitelistExceptIdle.contains(packageName);
         }
@@ -228,8 +218,7 @@
             return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
                     + WORKING_SET_THRESHOLD + "/"
                     + FREQUENT_THRESHOLD + "/"
-                    + RARE_THRESHOLD + ","
-                    + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
+                    + RARE_THRESHOLD;
         }
 
         @Override
@@ -273,13 +262,6 @@
         } catch (PackageManager.NameNotFoundException nnfe) {}
     }
 
-    private void setChargingState(AppStandbyController controller, boolean charging) {
-        mInjector.mIsCharging = charging;
-        if (controller != null) {
-            controller.setChargingState(charging);
-        }
-    }
-
     private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
         mInjector.mIsAppIdleEnabled = enabled;
         if (controller != null) {
@@ -296,7 +278,6 @@
         controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
         mInjector.setDisplayOn(false);
         mInjector.setDisplayOn(true);
-        setChargingState(controller, false);
         controller.checkIdleStates(USER_ID);
         assertNotEquals(STANDBY_BUCKET_EXEMPTED,
                 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
@@ -314,65 +295,6 @@
         MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
         mInjector = new MyInjector(myContext, Looper.getMainLooper());
         mController = setupController();
-        setChargingState(mController, false);
-    }
-
-    private class TestParoleListener extends UsageStatsManagerInternal.AppIdleStateChangeListener {
-        private boolean mOnParole = false;
-        private CountDownLatch mLatch;
-        private long mLastParoleChangeTime;
-        private boolean mIsExpecting = false;
-        private boolean mExpectedParoleState;
-
-        public boolean getParoleState() {
-            synchronized (this) {
-                return mOnParole;
-            }
-        }
-
-        public void rearmLatch() {
-            synchronized (this) {
-                mLatch = new CountDownLatch(1);
-                mIsExpecting = false;
-            }
-        }
-
-        public void rearmLatch(boolean expectedParoleState) {
-            synchronized (this) {
-                mLatch = new CountDownLatch(1);
-                mIsExpecting = true;
-                mExpectedParoleState = expectedParoleState;
-            }
-        }
-
-        public void awaitOnLatch(long time) throws Exception {
-            mLatch.await(time, TimeUnit.MILLISECONDS);
-        }
-
-        public long getLastParoleChangeTime() {
-            synchronized (this) {
-                return mLastParoleChangeTime;
-            }
-        }
-
-        @Override
-        public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
-                int bucket, int reason) {
-        }
-
-        @Override
-        public void onParoleStateChanged(boolean isParoleOn) {
-            synchronized (this) {
-                // Only record information if it is being looked for
-                if (mLatch != null && mLatch.getCount() > 0) {
-                    mOnParole = isParoleOn;
-                    mLastParoleChangeTime = getCurrentTime();
-                    if (!mIsExpecting || isParoleOn == mExpectedParoleState) {
-                        mLatch.countDown();
-                    }
-                }
-            }
-        }
     }
 
     @Test
@@ -383,133 +305,6 @@
                         mInjector.mElapsedRealtime, false));
     }
 
-    @Test
-    public void testCharging() throws Exception {
-        long startTime;
-        TestParoleListener paroleListener = new TestParoleListener();
-        long marginOfError = 200;
-
-        // Charging
-        paroleListener.rearmLatch();
-        mController.addListener(paroleListener);
-        startTime = getCurrentTime();
-        setChargingState(mController, true);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-        // Parole will only be granted after device has been charging for a sufficient amount of
-        // time.
-        assertEquals(STABLE_CHARGING_THRESHOLD,
-                paroleListener.getLastParoleChangeTime() - startTime,
-                marginOfError);
-
-        // Discharging
-        paroleListener.rearmLatch();
-        startTime = getCurrentTime();
-        setChargingState(mController, false);
-        mController.checkIdleStates(USER_ID);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertFalse(paroleListener.getParoleState());
-        // Parole should be revoked immediately
-        assertEquals(0,
-                paroleListener.getLastParoleChangeTime() - startTime,
-                marginOfError);
-
-        // Brief Charging
-        paroleListener.rearmLatch();
-        setChargingState(mController, true);
-        setChargingState(mController, false);
-        // Device stopped charging before the stable charging threshold.
-        // Parole should not be granted at the end of the threshold
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertFalse(paroleListener.getParoleState());
-
-        // Charging Again
-        paroleListener.rearmLatch();
-        startTime = getCurrentTime();
-        setChargingState(mController, true);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.getParoleState());
-        assertTrue(paroleListener.mOnParole);
-        assertEquals(STABLE_CHARGING_THRESHOLD,
-                paroleListener.getLastParoleChangeTime() - startTime,
-                marginOfError);
-    }
-
-    @Test
-    public void testEnabledState() throws Exception {
-        TestParoleListener paroleListener = new TestParoleListener();
-        paroleListener.rearmLatch(true);
-        mController.addListener(paroleListener);
-        long lastUpdateTime;
-
-        // Test that listeners are notified if enabled changes when the device is not in parole.
-        setChargingState(mController, false);
-
-        // Start off not enabled. Device is effectively in permanent parole.
-        setAppIdleEnabled(mController, false);
-        // Since AppStandbyController uses a handler to notify listeners of a state change, there is
-        // some inherent latency between changing the state and getting the notification. We need to
-        // wait until the paroleListener has been notified that parole is on before continuing with
-        // the test.
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-
-        // Enable controller
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, true);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertFalse(paroleListener.mOnParole);
-        lastUpdateTime = paroleListener.getLastParoleChangeTime();
-
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, true);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertFalse(paroleListener.mOnParole);
-        // Make sure AppStandbyController doesn't notify listeners when there's no change.
-        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
-
-        // Disable controller
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, false);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-        lastUpdateTime = paroleListener.getLastParoleChangeTime();
-
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, false);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-        // Make sure AppStandbyController doesn't notify listeners when there's no change.
-        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
-
-
-        // Test that listeners aren't notified if enabled status changes when the device is already
-        // in parole.
-
-        // A device is in parole whenever it's charging.
-        setChargingState(mController, true);
-
-        // Start off not enabled.
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, false);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-        lastUpdateTime = paroleListener.getLastParoleChangeTime();
-
-        // Test that toggling doesn't notify the listener.
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, true);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
-
-        paroleListener.rearmLatch();
-        setAppIdleEnabled(mController, false);
-        paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
-        assertTrue(paroleListener.mOnParole);
-        assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
-    }
-
     private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
         mInjector.mElapsedRealtime = elapsedTime;
         controller.checkIdleStates(USER_ID);
@@ -804,8 +599,6 @@
 
     @Test
     public void testSystemInteractionTimeout() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
         // Fast forward to RARE
         mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
@@ -829,8 +622,6 @@
 
     @Test
     public void testInitialForegroundServiceTimeout() throws Exception {
-        setChargingState(mController, false);
-
         mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
         // Make sure app is in NEVER bucket
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index ecee709..2cd207f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -97,8 +97,6 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
@@ -191,11 +189,6 @@
                     event.mPackage = packageName;
                     reportEventOrAddToQueue(userId, event);
                 }
-
-                @Override
-                public void onParoleStateChanged(boolean isParoleOn) {
-
-                }
             };
 
     public UsageStatsService(Context context) {
@@ -1426,7 +1419,7 @@
                     Binder.getCallingUid(), userId);
             final long token = Binder.clearCallingIdentity();
             try {
-                return mAppStandby.isAppIdleFilteredOrParoled(
+                return mAppStandby.isAppIdleFiltered(
                         packageName, userId,
                         SystemClock.elapsedRealtime(), obfuscateInstantApps);
             } finally {
@@ -1995,11 +1988,6 @@
         }
 
         @Override
-        public boolean isAppIdleParoleOn() {
-            return mAppStandby.isParoledOrCharging();
-        }
-
-        @Override
         public void prepareShutdown() {
             // This method *WILL* do IO work, but we must block until it is finished or else
             // we might not shutdown cleanly. This is ok to do with the 'am' lock held, because
@@ -2015,7 +2003,6 @@
         @Override
         public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
             mAppStandby.addListener(listener);
-            listener.onParoleStateChanged(isAppIdleParoleOn());
         }
 
         @Override
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
index cf120cf..59f4d56 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
@@ -33,6 +33,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -162,8 +163,8 @@
         @Override
         public boolean equals(Object other) {
             if (other instanceof BaseWithActivityRecordData) {
-                return activityRecordSnapshot.equals(
-                        ((BaseWithActivityRecordData)other).activityRecordSnapshot) &&
+                return (Arrays.equals(activityRecordSnapshot,
+                      ((BaseWithActivityRecordData)other).activityRecordSnapshot)) &&
                         super.equals(other);
             }
             return false;
@@ -171,7 +172,7 @@
 
         @Override
         protected String toStringBody() {
-            return ", " + activityRecordSnapshot.toString();
+            return ", " + new String(activityRecordSnapshot);
         }
 
         @Override
@@ -208,7 +209,7 @@
 
         @Override
         protected String toStringBody() {
-            return ", temperature=" + Integer.toString(temperature);
+            return super.toStringBody() + ", temperature=" + Integer.toString(temperature);
         }
 
         @Override
@@ -235,7 +236,7 @@
 
         @Override
         public boolean equals(Object other) {
-            if (other instanceof ActivityLaunched) {
+            if (other instanceof ActivityLaunchFinished) {
                 return timestampNs == ((ActivityLaunchFinished)other).timestampNs &&
                        super.equals(other);
             }
@@ -244,7 +245,7 @@
 
         @Override
         protected String toStringBody() {
-            return ", timestampNs=" + Long.toString(timestampNs);
+            return super.toStringBody() + ", timestampNs=" + Long.toString(timestampNs);
         }
 
         @Override
@@ -271,8 +272,8 @@
         @Override
         public boolean equals(Object other) {
             if (other instanceof ActivityLaunchCancelled) {
-                return Objects.equals(activityRecordSnapshot,
-                        ((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
+                return Arrays.equals(activityRecordSnapshot,
+                    ((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
                         super.equals(other);
             }
             return false;
@@ -280,7 +281,7 @@
 
         @Override
         protected String toStringBody() {
-            return ", " + activityRecordSnapshot.toString();
+            return super.toStringBody() + ", " + new String(activityRecordSnapshot);
         }
 
         @Override
@@ -325,7 +326,7 @@
 
         @Override
         protected String toStringBody() {
-            return ", timestampNs=" + Long.toString(timestampNs);
+            return super.toStringBody() + ", timestampNs=" + Long.toString(timestampNs);
         }
 
         @Override
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/AppLaunchEventTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/AppLaunchEventTest.kt
new file mode 100644
index 0000000..51e407d
--- /dev/null
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/AppLaunchEventTest.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 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.google.android.startop.iorap
+
+import android.content.Intent;
+import android.net.Uri
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.test.filters.SmallTest
+import com.google.android.startop.iorap.AppLaunchEvent;
+import com.google.android.startop.iorap.AppLaunchEvent.ActivityLaunched
+import com.google.android.startop.iorap.AppLaunchEvent.ActivityLaunchCancelled
+import com.google.android.startop.iorap.AppLaunchEvent.ActivityLaunchFinished
+import com.google.android.startop.iorap.AppLaunchEvent.IntentStarted;
+import com.google.android.startop.iorap.AppLaunchEvent.IntentFailed;
+import com.google.android.startop.iorap.AppLaunchEvent.ReportFullyDrawn
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+
+/**
+ * Basic unit tests to test all of the [AppLaunchEvent]s in [com.google.android.startop.iorap].
+ */
+@SmallTest
+class AppLaunchEventTest {
+  /**
+   * Test for IntentStarted.
+   */
+  @Test
+  fun testIntentStarted() {
+    var intent = Intent()
+    val valid = IntentStarted(/* sequenceId= */2L, intent, /* timestampNs= */ 1L)
+    val copy = IntentStarted(/* sequenceId= */2L, intent, /* timestampNs= */ 1L)
+    val noneCopy1 = IntentStarted(/* sequenceId= */1L, intent, /* timestampNs= */ 1L)
+    val noneCopy2 = IntentStarted(/* sequenceId= */2L, intent, /* timestampNs= */ 2L)
+    val noneCopy3 = IntentStarted(/* sequenceId= */2L, Intent(), /* timestampNs= */ 1L)
+
+    // equals(Object other)
+    assertThat(valid).isEqualTo(copy)
+    assertThat(valid).isNotEqualTo(noneCopy1)
+    assertThat(valid).isNotEqualTo(noneCopy2)
+    assertThat(valid).isNotEqualTo(noneCopy3)
+
+    // test toString()
+    val result = valid.toString()
+    assertThat(result).isEqualTo("IntentStarted{sequenceId=2, intent=Intent {  } , timestampNs=1}")
+  }
+
+  /**
+   * Test for IntentFailed.
+   */
+  @Test
+  fun testIntentFailed() {
+    val valid = IntentFailed(/* sequenceId= */2L)
+    val copy = IntentFailed(/* sequenceId= */2L)
+    val noneCopy = IntentFailed(/* sequenceId= */1L)
+
+    // equals(Object other)
+    assertThat(valid).isEqualTo(copy)
+    assertThat(valid).isNotEqualTo(noneCopy)
+
+    // test toString()
+    val result = valid.toString()
+    assertThat(result).isEqualTo("IntentFailed{sequenceId=2}")
+  }
+
+  /**
+   * Test for ActivityLaunched.
+   */
+  @Test
+  fun testActivityLaunched() {
+    //var activityRecord =
+    val valid = ActivityLaunched(/* sequenceId= */2L, "test".toByteArray(),
+      /* temperature= */ 0)
+    val copy = ActivityLaunched(/* sequenceId= */2L, "test".toByteArray(),
+      /* temperature= */ 0)
+    val noneCopy1 = ActivityLaunched(/* sequenceId= */1L, "test".toByteArray(),
+      /* temperature= */ 0)
+    val noneCopy2 = ActivityLaunched(/* sequenceId= */1L, "test".toByteArray(),
+      /* temperature= */ 1)
+    val noneCopy3 = ActivityLaunched(/* sequenceId= */1L, "test1".toByteArray(),
+      /* temperature= */ 0)
+
+    // equals(Object other)
+    assertThat(valid).isEqualTo(copy)
+    assertThat(valid).isNotEqualTo(noneCopy1)
+    assertThat(valid).isNotEqualTo(noneCopy2)
+    assertThat(valid).isNotEqualTo(noneCopy3)
+
+    // test toString()
+    val result = valid.toString()
+    assertThat(result).isEqualTo("ActivityLaunched{sequenceId=2, test, temperature=0}")
+  }
+
+
+  /**
+   * Test for ActivityLaunchFinished.
+   */
+  @Test
+  fun testActivityLaunchFinished() {
+    val valid = ActivityLaunchFinished(/* sequenceId= */2L, "test".toByteArray(),
+      /* timestampNs= */ 1L)
+    val copy = ActivityLaunchFinished(/* sequenceId= */2L, "test".toByteArray(),
+      /* timestampNs= */ 1L)
+    val noneCopy1 = ActivityLaunchFinished(/* sequenceId= */1L, "test".toByteArray(),
+      /* timestampNs= */ 1L)
+    val noneCopy2 = ActivityLaunchFinished(/* sequenceId= */1L, "test".toByteArray(),
+      /* timestampNs= */ 2L)
+    val noneCopy3 = ActivityLaunchFinished(/* sequenceId= */2L, "test1".toByteArray(),
+      /* timestampNs= */ 1L)
+
+    // equals(Object other)
+    assertThat(valid).isEqualTo(copy)
+    assertThat(valid).isNotEqualTo(noneCopy1)
+    assertThat(valid).isNotEqualTo(noneCopy2)
+    assertThat(valid).isNotEqualTo(noneCopy3)
+
+    // test toString()
+    val result = valid.toString()
+    assertThat(result).isEqualTo("ActivityLaunchFinished{sequenceId=2, test, timestampNs=1}")
+  }
+
+  /**
+   * Test for ActivityLaunchCancelled.
+   */
+  @Test
+  fun testActivityLaunchCancelled() {
+    val valid = ActivityLaunchCancelled(/* sequenceId= */2L, "test".toByteArray())
+    val copy = ActivityLaunchCancelled(/* sequenceId= */2L, "test".toByteArray())
+    val noneCopy1 = ActivityLaunchCancelled(/* sequenceId= */1L, "test".toByteArray())
+    val noneCopy2 = ActivityLaunchCancelled(/* sequenceId= */2L, "test1".toByteArray())
+
+    // equals(Object other)
+    assertThat(valid).isEqualTo(copy)
+    assertThat(valid).isNotEqualTo(noneCopy1)
+    assertThat(valid).isNotEqualTo(noneCopy2)
+
+    // test toString()
+    val result = valid.toString()
+    assertThat(result).isEqualTo("ActivityLaunchCancelled{sequenceId=2, test}")
+  }
+
+  /**
+   * Test for ReportFullyDrawn.
+   */
+  @Test
+  fun testReportFullyDrawn() {
+    val valid = ReportFullyDrawn(/* sequenceId= */2L, "test".toByteArray(), /* timestampNs= */ 1L)
+    val copy = ReportFullyDrawn(/* sequenceId= */2L, "test".toByteArray(), /* timestampNs= */ 1L)
+    val noneCopy1 = ReportFullyDrawn(/* sequenceId= */1L, "test".toByteArray(),
+      /* timestampNs= */ 1L)
+    val noneCopy2 = ReportFullyDrawn(/* sequenceId= */1L, "test".toByteArray(),
+      /* timestampNs= */ 1L)
+    val noneCopy3 = ReportFullyDrawn(/* sequenceId= */2L, "test1".toByteArray(),
+      /* timestampNs= */ 1L)
+
+    // equals(Object other)
+    assertThat(valid).isEqualTo(copy)
+    assertThat(valid).isNotEqualTo(noneCopy1)
+    assertThat(valid).isNotEqualTo(noneCopy2)
+    assertThat(valid).isNotEqualTo(noneCopy3)
+
+    // test toString()
+    val result = valid.toString()
+    assertThat(result).isEqualTo("ReportFullyDrawn{sequenceId=2, test, timestampNs=1}")
+  }
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 5e71416..3f348a4 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -728,6 +728,7 @@
         }
 
         /** {@hide} */
+        @TestApi
         public String getTelecomCallId() {
             return mTelecomCallId;
         }
@@ -2137,6 +2138,9 @@
         }
 
         int state = parcelableCall.getState();
+        if (mTargetSdkVersion < Phone.SDK_VERSION_R && state == Call.STATE_SIMULATED_RINGING) {
+            state = Call.STATE_RINGING;
+        }
         boolean stateChanged = mState != state;
         if (stateChanged) {
             mState = state;
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 0d97567..ef1c790 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -374,6 +374,8 @@
                         new ComponentName(getPackageName(), getClass().getName()));
             } else if (response.getSilenceCall()) {
                 mCallScreeningAdapter.silenceCall(callDetails.getTelecomCallId());
+            } else if (response.getShouldScreenCallFurther()) {
+                mCallScreeningAdapter.screenCallFurther(callDetails.getTelecomCallId());
             } else {
                 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
             }
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 0cc052e..2ecdb30 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -21,7 +21,6 @@
 import android.bluetooth.BluetoothDevice;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.util.ArrayMap;
 
 import java.util.Collections;
@@ -111,6 +110,10 @@
         public void onSilenceRinger(Phone phone) { }
     }
 
+    // TODO: replace all usages of this with the actual R constant from Build.VERSION_CODES
+    /** @hide */
+    public static final int SDK_VERSION_R = 30;
+
     // A Map allows us to track each Call by its Telecom-specified call ID
     private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>();
 
@@ -143,6 +146,12 @@
     }
 
     final void internalAddCall(ParcelableCall parcelableCall) {
+        if (mTargetSdkVersion < SDK_VERSION_R
+                && parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) {
+            Log.i(this, "Skipping adding audio processing call for sdk compatibility");
+            return;
+        }
+
         Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
                 parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
         mCallByTelecomCallId.put(parcelableCall.getId(), call);
@@ -150,7 +159,7 @@
         checkCallTree(parcelableCall);
         call.internalUpdate(parcelableCall, mCallByTelecomCallId);
         fireCallAdded(call);
-     }
+    }
 
     final void internalRemoveCall(Call call) {
         mCallByTelecomCallId.remove(call.internalGetCallId());
@@ -164,12 +173,28 @@
     }
 
     final void internalUpdateCall(ParcelableCall parcelableCall) {
-         Call call = mCallByTelecomCallId.get(parcelableCall.getId());
-         if (call != null) {
-             checkCallTree(parcelableCall);
-             call.internalUpdate(parcelableCall, mCallByTelecomCallId);
-         }
-     }
+        if (mTargetSdkVersion < SDK_VERSION_R
+                && parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) {
+            Log.i(this, "removing audio processing call during update for sdk compatibility");
+            Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+            if (call != null) {
+                internalRemoveCall(call);
+            }
+            return;
+        }
+
+        Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+        if (call != null) {
+            checkCallTree(parcelableCall);
+            call.internalUpdate(parcelableCall, mCallByTelecomCallId);
+        } else {
+            // This call may have come out of audio processing. Try adding it if our target sdk
+            // version is low enough.
+            if (mTargetSdkVersion < SDK_VERSION_R) {
+                internalAddCall(parcelableCall);
+            }
+        }
+    }
 
     final void internalSetPostDialWait(String telecomId, String remaining) {
         Call call = mCallByTelecomCallId.get(telecomId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9e60afc..047b220 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -526,6 +526,15 @@
             "default_vm_number_roaming_string";
 
     /**
+     * Where there is no preloaded voicemail number on a SIM card, specifies the carrier's default
+     * voicemail number while the device is both roaming and not registered for IMS.
+     * When empty string, no default voicemail number is specified for roaming network and
+     * unregistered state in IMS.
+     */
+    public static final String KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING =
+            "default_vm_number_roaming_and_ims_unregistered_string";
+
+    /**
      * Flag that specifies to use the user's own phone number as the voicemail number when there is
      * no pre-loaded voicemail number on the SIM card.
      * <p>
@@ -3232,6 +3241,7 @@
         sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
         sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
         sDefaults.putString(KEY_DEFAULT_VM_NUMBER_ROAMING_STRING, "");
+        sDefaults.putString(KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING, "");
         sDefaults.putBoolean(KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL, false);
         sDefaults.putBoolean(KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, true);
         sDefaults.putBoolean(KEY_VILTE_DATA_IS_METERED_BOOL, true);
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 3515053..325c1c0 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@
 
 
 
-    // Code below generated by codegen v1.0.8.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -58,7 +58,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(android.os.Parcel dest, int flags) {
+    public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -72,7 +72,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    protected HierrarchicalDataClassBase(android.os.Parcel in) {
+    protected HierrarchicalDataClassBase(@android.annotation.NonNull android.os.Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -92,14 +92,14 @@
         }
 
         @Override
-        public HierrarchicalDataClassBase createFromParcel(android.os.Parcel in) {
+        public HierrarchicalDataClassBase createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
             return new HierrarchicalDataClassBase(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1570828332402L,
-            codegenVersion = "1.0.8",
+            time = 1571258914826L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
             inputSignatures = "private  int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index c867409..6c92009 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@
 
 
 
-    // Code below generated by codegen v1.0.8.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -74,7 +74,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(android.os.Parcel dest, int flags) {
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -90,7 +90,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    protected HierrarchicalDataClassChild(android.os.Parcel in) {
+    protected HierrarchicalDataClassChild(@NonNull android.os.Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -114,14 +114,14 @@
         }
 
         @Override
-        public HierrarchicalDataClassChild createFromParcel(android.os.Parcel in) {
+        public HierrarchicalDataClassChild createFromParcel(@NonNull android.os.Parcel in) {
             return new HierrarchicalDataClassChild(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1570828333399L,
-            codegenVersion = "1.0.8",
+            time = 1571258915848L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
             inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 8d097a0..36def8a 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -52,7 +52,7 @@
 
 
 
-    // Code below generated by codegen v1.0.8.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -161,7 +161,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -185,7 +185,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    protected ParcelAllTheThingsDataClass(Parcel in) {
+    protected ParcelAllTheThingsDataClass(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -237,7 +237,7 @@
         }
 
         @Override
-        public ParcelAllTheThingsDataClass createFromParcel(Parcel in) {
+        public ParcelAllTheThingsDataClass createFromParcel(@NonNull Parcel in) {
             return new ParcelAllTheThingsDataClass(in);
         }
     };
@@ -410,8 +410,8 @@
     }
 
     @DataClass.Generated(
-            time = 1570828331396L,
-            codegenVersion = "1.0.8",
+            time = 1571258913802L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
             inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index d014d6d..c444d61 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@
 
 
 
-    // Code below generated by codegen v1.0.8.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -1119,7 +1119,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public boolean equals(Object o) {
+    public boolean equals(@Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
         // boolean fieldNameEquals(SampleDataClass other) { ... }
         // boolean fieldNameEquals(FieldType otherValue) { ... }
@@ -1184,8 +1184,8 @@
 
     @DataClass.Generated.Member
     void forEachField(
-            DataClass.PerIntFieldAction<SampleDataClass> actionInt,
-            DataClass.PerObjectFieldAction<SampleDataClass> actionObject) {
+            @NonNull DataClass.PerIntFieldAction<SampleDataClass> actionInt,
+            @NonNull DataClass.PerObjectFieldAction<SampleDataClass> actionObject) {
         actionInt.acceptInt(this, "num", mNum);
         actionInt.acceptInt(this, "num2", mNum2);
         actionInt.acceptInt(this, "num4", mNum4);
@@ -1211,7 +1211,7 @@
     /** @deprecated May cause boxing allocations - use with caution! */
     @Deprecated
     @DataClass.Generated.Member
-    void forEachField(DataClass.PerObjectFieldAction<SampleDataClass> action) {
+    void forEachField(@NonNull DataClass.PerObjectFieldAction<SampleDataClass> action) {
         action.acceptObject(this, "num", mNum);
         action.acceptObject(this, "num2", mNum2);
         action.acceptObject(this, "num4", mNum4);
@@ -1258,7 +1258,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -1297,7 +1297,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ SampleDataClass(Parcel in) {
+    /* package-private */ SampleDataClass(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -1420,7 +1420,7 @@
         }
 
         @Override
-        public SampleDataClass createFromParcel(Parcel in) {
+        public SampleDataClass createFromParcel(@NonNull Parcel in) {
             return new SampleDataClass(in);
         }
     };
@@ -1872,8 +1872,8 @@
     }
 
     @DataClass.Generated(
-            time = 1570828329319L,
-            codegenVersion = "1.0.8",
+            time = 1571258911688L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
             inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 1c87e8f..55feae7 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
 
 
 
-    // Code below generated by codegen v1.0.8.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -142,7 +142,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -158,7 +158,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    protected SampleWithCustomBuilder(Parcel in) {
+    protected SampleWithCustomBuilder(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -184,7 +184,7 @@
         }
 
         @Override
-        public SampleWithCustomBuilder createFromParcel(Parcel in) {
+        public SampleWithCustomBuilder createFromParcel(@NonNull Parcel in) {
             return new SampleWithCustomBuilder(in);
         }
     };
@@ -253,8 +253,8 @@
     }
 
     @DataClass.Generated(
-            time = 1570828330331L,
-            codegenVersion = "1.0.8",
+            time = 1571258912752L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
             inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nprivate static  java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate  void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 27af37f..b967f19 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -51,7 +51,7 @@
 
 
 
-    // Code below generated by codegen v1.0.8.
+    // Code below generated by codegen v1.0.9.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -65,8 +65,8 @@
 
 
     @DataClass.Generated(
-            time = 1570828334384L,
-            codegenVersion = "1.0.8",
+            time = 1571258916868L,
+            codegenVersion = "1.0.9",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
             inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
     @Deprecated
diff --git a/tests/FlickerTests/TEST_MAPPING b/tests/FlickerTests/TEST_MAPPING
index 55a6147..f34c432 100644
--- a/tests/FlickerTests/TEST_MAPPING
+++ b/tests/FlickerTests/TEST_MAPPING
@@ -1,7 +1,8 @@
 {
   "postsubmit": [
     {
-      "name": "FlickerTests"
+      "name": "FlickerTests",
+      "keywords": ["primary-device"]
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 9e6ac8e..8b97f61 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -92,7 +92,7 @@
      * Enable rollback phase.
      */
     @Test
-    public void testBadApkOnlyEnableRollback() throws Exception {
+    public void testBadApkOnly_Phase1() throws Exception {
         Uninstall.packages(TestApp.A);
         assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
@@ -101,9 +101,6 @@
         InstallUtils.processUserData(TestApp.A);
 
         Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit();
-
-        // At this point, the host test driver will reboot the device and run
-        // testBadApkOnlyConfirmEnableRollback().
     }
 
     /**
@@ -111,7 +108,7 @@
      * Confirm that rollback was successfully enabled.
      */
     @Test
-    public void testBadApkOnlyConfirmEnableRollback() throws Exception {
+    public void testBadApkOnly_Phase2() throws Exception {
         assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
         InstallUtils.processUserData(TestApp.A);
 
@@ -122,9 +119,6 @@
         assertThat(rollback).packagesContainsExactly(
                 Rollback.from(TestApp.A2).to(TestApp.A1));
         assertThat(rollback.isStaged()).isTrue();
-
-        // At this point, the host test driver will run
-        // testBadApkOnlyTriggerRollback().
     }
 
     /**
@@ -133,15 +127,14 @@
      * rebooting the test out from under it.
      */
     @Test
-    public void testBadApkOnlyTriggerRollback() throws Exception {
+    public void testBadApkOnly_Phase3() throws Exception {
         // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
         RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
 
-        // We expect the device to be rebooted automatically. Wait for that to
-        // happen. At that point, the host test driver will wait for the
-        // device to come back up and run testApkOnlyConfirmRollback().
+        // We expect the device to be rebooted automatically. Wait for that to happen.
         Thread.sleep(30 * 1000);
 
+        // Raise an error anyway if reboot didn't happen.
         fail("watchdog did not trigger reboot");
     }
 
@@ -150,7 +143,7 @@
      * Confirm rollback phase.
      */
     @Test
-    public void testBadApkOnlyConfirmRollback() throws Exception {
+    public void testBadApkOnly_Phase4() throws Exception {
         assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
         InstallUtils.processUserData(TestApp.A);
 
@@ -177,8 +170,11 @@
                         networkStack)).isNull();
     }
 
+    /**
+     * Stage install ModuleMetadata package to simulate a Mainline module update.
+     */
     @Test
-    public void installModuleMetadataPackage() throws Exception {
+    public void testNativeWatchdogTriggersRollback_Phase1() throws Exception {
         resetModuleMetadataPackage();
         Context context = InstrumentationRegistry.getContext();
         PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo(
@@ -192,6 +188,26 @@
                 + metadataApkPath);
     }
 
+    /**
+     * Verify the rollback is available.
+     */
+    @Test
+    public void testNativeWatchdogTriggersRollback_Phase2() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                        MODULE_META_DATA_PACKAGE)).isNotNull();
+    }
+
+    /**
+     * Verify the rollback is committed after crashing.
+     */
+    @Test
+    public void testNativeWatchdogTriggersRollback_Phase3() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                        MODULE_META_DATA_PACKAGE)).isNotNull();
+    }
+
     @Test
     public void assertNetworkStackRollbackAvailable() throws Exception {
         RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -213,20 +229,6 @@
                         getNetworkStackPackageName())).isNull();
     }
 
-    @Test
-    public void assertModuleMetadataRollbackAvailable() throws Exception {
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
-                        MODULE_META_DATA_PACKAGE)).isNotNull();
-    }
-
-    @Test
-    public void assertModuleMetadataRollbackCommitted() throws Exception {
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
-                        MODULE_META_DATA_PACKAGE)).isNotNull();
-    }
-
     private String getNetworkStackPackageName() {
         Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
         ComponentName comp = intent.resolveSystemService(
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index bc98f06..2043027 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -68,35 +68,35 @@
      */
     @Test
     public void testBadApkOnly() throws Exception {
-        runPhase("testBadApkOnlyEnableRollback");
+        runPhase("testBadApkOnly_Phase1");
         getDevice().reboot();
-        runPhase("testBadApkOnlyConfirmEnableRollback");
+        runPhase("testBadApkOnly_Phase2");
         try {
             // This is expected to fail due to the device being rebooted out
             // from underneath the test. If this fails for reasons other than
             // the device reboot, those failures should result in failure of
             // the testApkOnlyConfirmRollback phase.
             CLog.logAndDisplay(LogLevel.INFO, "testBadApkOnlyTriggerRollback is expected to fail");
-            runPhase("testBadApkOnlyTriggerRollback");
+            runPhase("testBadApkOnly_Phase3");
         } catch (AssertionError e) {
             // AssertionError is expected.
         }
 
         getDevice().waitForDeviceAvailable();
 
-        runPhase("testBadApkOnlyConfirmRollback");
+        runPhase("testBadApkOnly_Phase4");
     }
 
     @Test
     public void testNativeWatchdogTriggersRollback() throws Exception {
         //Stage install ModuleMetadata package - this simulates a Mainline module update
-        runPhase("installModuleMetadataPackage");
+        runPhase("testNativeWatchdogTriggersRollback_Phase1");
 
         // Reboot device to activate staged package
         getDevice().reboot();
         getDevice().waitForDeviceAvailable();
 
-        runPhase("assertModuleMetadataRollbackAvailable");
+        runPhase("testNativeWatchdogTriggersRollback_Phase2");
 
         // crash system_server enough times to trigger a rollback
         crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -113,7 +113,7 @@
         getDevice().waitForDeviceAvailable();
 
         // verify rollback committed
-        runPhase("assertModuleMetadataRollbackCommitted");
+        runPhase("testNativeWatchdogTriggersRollback_Phase3");
     }
 
     /**
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 0ebb3cf..431f378 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -417,7 +417,7 @@
     if (!isMethodGenerationSuppressed("writeToParcel", Parcel, "int")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
-        "public void writeToParcel($Parcel dest, int flags)" {
+        "public void writeToParcel(@$NonNull $Parcel dest, int flags)" {
             +"// You can override field parcelling by defining methods like:"
             +"// void parcelFieldName(Parcel dest, int flags) { ... }"
             +""
@@ -473,7 +473,7 @@
         +"/** @hide */"
         +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})"
         +GENERATED_MEMBER_HEADER
-        "$visibility $ClassName($Parcel in) {" {
+        "$visibility $ClassName(@$NonNull $Parcel in) {" {
             +"// You can override field unparcelling by defining methods like:"
             +"// static FieldType unparcelFieldName(Parcel in) { ... }"
             +""
@@ -598,7 +598,7 @@
             }
 
             +"@Override"
-            "public $ClassName createFromParcel($Parcel in)" {
+            "public $ClassName createFromParcel(@$NonNull $Parcel in)" {
                 +"return new $ClassName(in);"
             }
             rmEmptyLine()
@@ -611,7 +611,7 @@
     if (!isMethodGenerationSuppressed("equals", "Object")) {
         +"@Override"
         +GENERATED_MEMBER_HEADER
-        "public boolean equals(Object o)" {
+        "public boolean equals(@$Nullable Object o)" {
             +"// You can override field equality logic by defining either of the methods like:"
             +"// boolean fieldNameEquals($ClassName other) { ... }"
             +"// boolean fieldNameEquals(FieldType otherValue) { ... }"
@@ -904,7 +904,7 @@
         usedSpecializationsSet.toList().forEachLastAware { specType, isLast ->
             val SpecType = specType.capitalize()
             val ActionClass = classRef("com.android.internal.util.DataClass.Per${SpecType}FieldAction")
-            +"$ActionClass<$ClassType> action$SpecType${if_(!isLast, ",")}"
+            +"@$NonNull $ActionClass<$ClassType> action$SpecType${if_(!isLast, ",")}"
         }
     }; " {" {
         usedSpecializations.forEachIndexed { i, specType ->
@@ -919,7 +919,7 @@
         +"/** @deprecated May cause boxing allocations - use with caution! */"
         +"@Deprecated"
         +GENERATED_MEMBER_HEADER
-        "void forEachField($PerObjectFieldAction<$ClassType> action)" {
+        "void forEachField(@$NonNull $PerObjectFieldAction<$ClassType> action)" {
             fields.forEachApply {
                 +"action.acceptObject(this, \"$nameLowerCamel\", $name);"
             }
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 8c4583f..3eb9e7b 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.8"
+const val CODEGEN_VERSION = "1.0.9"
 
 const val CANONICAL_BUILDER_CLASS = "Builder"
 const val BASE_BUILDER_CLASS = "BaseBuilder"