Merge "Extract out IMM.DelegateImpl#onViewFocusChanged()"
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 2682dd7..442c130 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -36,9 +36,11 @@
 
     /**
      * Cancel the jobs for a given uid (e.g. when app data is cleared)
+     *
+     * @param includeProxiedJobs Include jobs scheduled for this UID by other apps
      */
-    void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, int debugReasonCode,
-            String debugReason);
+    void cancelJobsForUid(int uid, boolean includeProxiedJobs,
+            @JobParameters.StopReason int reason, int debugReasonCode, String debugReason);
 
     /**
      * These are for activity manager to communicate to use what is currently performing backups.
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 f5c0ed9..bdd1fc54 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -970,12 +970,12 @@
                 // Has this package scheduled any jobs, such that we will take action
                 // if it were to be force-stopped?
                 if (pkgUid != -1) {
-                    List<JobStatus> jobsForUid;
+                    ArraySet<JobStatus> jobsForUid;
                     synchronized (mLock) {
                         jobsForUid = mJobs.getJobsByUid(pkgUid);
                     }
                     for (int i = jobsForUid.size() - 1; i >= 0; i--) {
-                        if (jobsForUid.get(i).getSourcePackageName().equals(pkgName)) {
+                        if (jobsForUid.valueAt(i).getSourcePackageName().equals(pkgName)) {
                             if (DEBUG) {
                                 Slog.d(TAG, "Restart query: package " + pkgName + " at uid "
                                         + pkgUid + " has jobs");
@@ -1292,10 +1292,11 @@
 
     public List<JobInfo> getPendingJobs(int uid) {
         synchronized (mLock) {
-            List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+            ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid);
             ArrayList<JobInfo> outList = new ArrayList<JobInfo>(jobs.size());
+            // Write out for loop to avoid addAll() creating an Iterator.
             for (int i = jobs.size() - 1; i >= 0; i--) {
-                JobStatus job = jobs.get(i);
+                final JobStatus job = jobs.valueAt(i);
                 outList.add(job.getJob());
             }
             return outList;
@@ -1304,9 +1305,9 @@
 
     public JobInfo getPendingJob(int uid, int jobId) {
         synchronized (mLock) {
-            List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+            ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid);
             for (int i = jobs.size() - 1; i >= 0; i--) {
-                JobStatus job = jobs.get(i);
+                JobStatus job = jobs.valueAt(i);
                 if (job.getJobId() == jobId) {
                     return job.getJob();
                 }
@@ -1348,7 +1349,7 @@
             Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
             return;
         }
-        final List<JobStatus> jobsForUid = new ArrayList<>();
+        final ArraySet<JobStatus> jobsForUid = new ArraySet<>();
         if (includeSchedulingApp) {
             mJobs.getJobsByUid(uid, jobsForUid);
         }
@@ -1356,7 +1357,7 @@
             mJobs.getJobsBySourceUid(uid, jobsForUid);
         }
         for (int i = jobsForUid.size() - 1; i >= 0; i--) {
-            final JobStatus job = jobsForUid.get(i);
+            final JobStatus job = jobsForUid.valueAt(i);
             final boolean shouldCancel =
                     (includeSchedulingApp
                             && job.getServiceComponent().getPackageName().equals(pkgName))
@@ -1368,14 +1369,16 @@
     }
 
     /**
-     * Entry point from client to cancel all jobs originating from their uid.
+     * Entry point from client to cancel all jobs scheduled for or from their uid.
      * This will remove the job from the master list, and cancel the job if it was staged for
      * execution or being executed.
      *
      * @param uid Uid to check against for removal of a job.
+     * @param includeSourceApp Whether to include jobs scheduled for this UID by another UID.
+     *                         If false, only jobs scheduled by this UID will be cancelled.
      */
-    public boolean cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
-            int internalReasonCode, String debugReason) {
+    public boolean cancelJobsForUid(int uid, boolean includeSourceApp,
+            @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
         if (uid == Process.SYSTEM_UID) {
             Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
             return false;
@@ -1383,9 +1386,15 @@
 
         boolean jobsCanceled = false;
         synchronized (mLock) {
-            final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
+            final ArraySet<JobStatus> jobsForUid = new ArraySet<>();
+            // Get jobs scheduled by the app.
+            mJobs.getJobsByUid(uid, jobsForUid);
+            if (includeSourceApp) {
+                // Get jobs scheduled for the app by someone else.
+                mJobs.getJobsBySourceUid(uid, jobsForUid);
+            }
             for (int i = 0; i < jobsForUid.size(); i++) {
-                JobStatus toRemove = jobsForUid.get(i);
+                JobStatus toRemove = jobsForUid.valueAt(i);
                 cancelJobImplLocked(toRemove, null, reason, internalReasonCode, debugReason);
                 jobsCanceled = true;
             }
@@ -2220,6 +2229,7 @@
                         updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                         if (disabled) {
                             cancelJobsForUid(uid,
+                                    /* includeSourceApp */ true,
                                     JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
                                     JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
                                     "uid gone");
@@ -2241,6 +2251,7 @@
                         final boolean disabled = message.arg2 != 0;
                         if (disabled) {
                             cancelJobsForUid(uid,
+                                    /* includeSourceApp */ true,
                                     JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
                                     JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
                                     "app uid idle");
@@ -2899,9 +2910,10 @@
         }
 
         @Override
-        public void cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
-                int internalReasonCode, String debugReason) {
-            JobSchedulerService.this.cancelJobsForUid(uid, reason, internalReasonCode, debugReason);
+        public void cancelJobsForUid(int uid, boolean includeProxiedJobs,
+                @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
+            JobSchedulerService.this.cancelJobsForUid(uid,
+                    includeProxiedJobs, reason, internalReasonCode, debugReason);
         }
 
         @Override
@@ -3273,6 +3285,8 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 JobSchedulerService.this.cancelJobsForUid(uid,
+                        // Documentation says only jobs scheduled BY the app will be cancelled
+                        /* includeSourceApp */ false,
                         JobParameters.STOP_REASON_CANCELLED_BY_APP,
                         JobParameters.INTERNAL_STOP_REASON_CANCELED,
                         "cancelAll() called by app, callingUid=" + uid);
@@ -3484,7 +3498,9 @@
 
         if (!hasJobId) {
             pw.println("Canceling all jobs for " + pkgName + " in user " + userId);
-            if (!cancelJobsForUid(pkgUid, JobParameters.STOP_REASON_USER,
+            if (!cancelJobsForUid(pkgUid,
+                    /* includeSourceApp */ false,
+                    JobParameters.STOP_REASON_USER,
                     JobParameters.INTERNAL_STOP_REASON_CANCELED,
                     "cancel shell command for package")) {
                 pw.println("No matching jobs found.");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index ff4d26d..f731b8d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -291,11 +291,11 @@
      * @return A list of all the jobs scheduled for the source app. Never null.
      */
     @NonNull
-    public List<JobStatus> getJobsBySourceUid(int sourceUid) {
+    public ArraySet<JobStatus> getJobsBySourceUid(int sourceUid) {
         return mJobSet.getJobsBySourceUid(sourceUid);
     }
 
-    public void getJobsBySourceUid(int sourceUid, @NonNull List<JobStatus> insertInto) {
+    public void getJobsBySourceUid(int sourceUid, @NonNull Set<JobStatus> insertInto) {
         mJobSet.getJobsBySourceUid(sourceUid, insertInto);
     }
 
@@ -304,11 +304,11 @@
      * @return All JobStatus objects for a given uid from the master list. Never null.
      */
     @NonNull
-    public List<JobStatus> getJobsByUid(int uid) {
+    public ArraySet<JobStatus> getJobsByUid(int uid) {
         return mJobSet.getJobsByUid(uid);
     }
 
-    public void getJobsByUid(int uid, @NonNull List<JobStatus> insertInto) {
+    public void getJobsByUid(int uid, @NonNull Set<JobStatus> insertInto) {
         mJobSet.getJobsByUid(uid, insertInto);
     }
 
@@ -1232,13 +1232,13 @@
             mJobsPerSourceUid = new SparseArray<>();
         }
 
-        public List<JobStatus> getJobsByUid(int uid) {
-            ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+        public ArraySet<JobStatus> getJobsByUid(int uid) {
+            ArraySet<JobStatus> matchingJobs = new ArraySet<>();
             getJobsByUid(uid, matchingJobs);
             return matchingJobs;
         }
 
-        public void getJobsByUid(int uid, List<JobStatus> insertInto) {
+        public void getJobsByUid(int uid, Set<JobStatus> insertInto) {
             ArraySet<JobStatus> jobs = mJobs.get(uid);
             if (jobs != null) {
                 insertInto.addAll(jobs);
@@ -1246,13 +1246,13 @@
         }
 
         @NonNull
-        public List<JobStatus> getJobsBySourceUid(int sourceUid) {
-            final ArrayList<JobStatus> result = new ArrayList<JobStatus>();
+        public ArraySet<JobStatus> getJobsBySourceUid(int sourceUid) {
+            final ArraySet<JobStatus> result = new ArraySet<>();
             getJobsBySourceUid(sourceUid, result);
             return result;
         }
 
-        public void getJobsBySourceUid(int sourceUid, List<JobStatus> insertInto) {
+        public void getJobsBySourceUid(int sourceUid, Set<JobStatus> insertInto) {
             final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid);
             if (jobs != null) {
                 insertInto.addAll(jobs);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index 9c16772..bbd661a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -50,7 +50,6 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.function.Predicate;
 
 /**
@@ -397,10 +396,10 @@
             return;
         }
         final long nowElapsed = sElapsedRealtimeClock.millis();
-        List<JobStatus> jobsByUid = mService.getJobStore().getJobsByUid(uid);
+        ArraySet<JobStatus> jobsByUid = mService.getJobStore().getJobsBySourceUid(uid);
         boolean hasPrefetch = false;
         for (int i = 0; i < jobsByUid.size(); i++) {
-            JobStatus js = jobsByUid.get(i);
+            JobStatus js = jobsByUid.valueAt(i);
             if (js.hasFlexibilityConstraint()) {
                 js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
                 hasPrefetch |= js.getJob().isPrefetch();
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 0f7e01b..94275ae 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -31,8 +31,6 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
-import com.android.server.SystemConfig;
-
 import java.util.List;
 
 /**
@@ -50,7 +48,7 @@
  * <overlayable name="OverlayableResourcesName" actor="overlay://namespace/actorName">
  * }</pre></p>
  *
- * <p>Actors are defined through {@link SystemConfig}. Only system packages can be used.
+ * <p>Actors are defined through SystemConfig. Only system packages can be used.
  * The namespace "android" is reserved for use by AOSP and any "android" definitions must
  * have an implementation on device that fulfill their intended functionality.</p>
  *
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e13f60c..2c28268 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -45,7 +45,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Parcelling;
 import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
-import com.android.server.SystemConfig;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -803,7 +802,6 @@
      */
     public static final int PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE = 1 << 2;
 
-
     /**
      * If false, {@link android.view.KeyEvent#KEYCODE_BACK} related events will be forwarded to
      * the Activities, Dialogs and Views and {@link android.app.Activity#onBackPressed()},
@@ -815,12 +813,24 @@
      */
     public static final int PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK = 1 << 3;
 
+    /**
+     * Whether or not this package is allowed to access hidden APIs. Replacement for legacy
+     * implementation of {@link #isPackageWhitelistedForHiddenApis()}.
+     *
+     * This is an internal flag and should never be used outside of this class. The real API for
+     * the hidden API enforcement policy is {@link #getHiddenApiEnforcementPolicy()}.
+     *
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS = 1 << 4;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
             PRIVATE_FLAG_EXT_PROFILEABLE,
             PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
             PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE,
             PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK,
+            PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationInfoPrivateFlagsExt {}
@@ -2222,7 +2232,7 @@
     }
 
     private boolean isPackageWhitelistedForHiddenApis() {
-        return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+        return (privateFlagsExt & PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS) != 0;
     }
 
     /**
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java
index eddb519..5de6d73 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/ui/RequestInfo.java
@@ -36,6 +36,12 @@
      */
     public static final @NonNull String EXTRA_REQUEST_INFO =
             "android.credentials.ui.extra.REQUEST_INFO";
+    /**
+     * The intent extra key for the {@code ResultReceiver} object when launching the UX
+     * activities.
+     */
+    public static final @NonNull String EXTRA_RESULT_RECEIVER =
+            "android.credentials.ui.extra.RESULT_RECEIVER";
 
     /** Type value for an executeGetCredential request. */
     public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET";
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 861a850..8873807 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2609,31 +2609,31 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="left">Input Format</th>
-     * <th align="left">Output Format</th>
-     * <th align="left">Capability</th>
+     * <th style="text-align: left;">Input Format</th>
+     * <th style="text-align: left;">Output Format</th>
+     * <th style="text-align: left;">Capability</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="left">PRIVATE_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#JPEG }</td>
+     * <td style="text-align: left;">PRIVATE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="left">PRIVATE_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: left;">PRIVATE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="left">YUV_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#JPEG }</td>
+     * <td style="text-align: left;">YUV_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="left">YUV_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: left;">YUV_REPROCESSING</td>
      * </tr>
      * </tbody>
      * </table>
@@ -2650,26 +2650,26 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="left">Input Format</th>
-     * <th align="left">Output Format</th>
-     * <th align="left">Capability</th>
+     * <th style="text-align: left;">Input Format</th>
+     * <th style="text-align: left;">Output Format</th>
+     * <th style="text-align: left;">Capability</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
-     * <td align="left">PRIVATE_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td style="text-align: left;">PRIVATE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="left">YUV_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#JPEG }</td>
+     * <td style="text-align: left;">YUV_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
-     * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
-     * <td align="left">YUV_REPROCESSING</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+     * <td style="text-align: left;">YUV_REPROCESSING</td>
      * </tr>
      * </tbody>
      * </table>
@@ -2705,60 +2705,60 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">Format</th>
-     * <th align="center">Size</th>
-     * <th align="center">Hardware Level</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">Format</th>
+     * <th style="text-align: center;">Size</th>
+     * <th style="text-align: center;">Hardware Level</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
-     * <td align="center">Any</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">1920x1080 (1080p)</td>
-     * <td align="center">Any</td>
-     * <td align="center">if 1080p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">1920x1080 (1080p)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;">if 1080p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">1280x720 (720)</td>
-     * <td align="center">Any</td>
-     * <td align="center">if 720p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">1280x720 (720)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;">if 720p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">640x480 (480p)</td>
-     * <td align="center">Any</td>
-     * <td align="center">if 480p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">640x480 (480p)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;">if 480p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">320x240 (240p)</td>
-     * <td align="center">Any</td>
-     * <td align="center">if 240p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">320x240 (240p)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;">if 240p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">all output sizes available for JPEG</td>
-     * <td align="center">FULL</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">all output sizes available for JPEG</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
-     * <td align="center">LIMITED</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">all output sizes available for JPEG, up to the maximum video size</td>
+     * <td style="text-align: center;">LIMITED</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">IMPLEMENTATION_DEFINED</td>
-     * <td align="center">same as YUV_420_888</td>
-     * <td align="center">Any</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">IMPLEMENTATION_DEFINED</td>
+     * <td style="text-align: center;">same as YUV_420_888</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * </tbody>
      * </table>
@@ -2773,66 +2773,66 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">Format</th>
-     * <th align="center">Size</th>
-     * <th align="center">Hardware Level</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">Format</th>
+     * <th style="text-align: center;">Size</th>
+     * <th style="text-align: center;">Hardware Level</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
-     * <td align="center">Any</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">JPEG</td>
-     * <td align="center">1920x1080 (1080p)</td>
-     * <td align="center">Any</td>
-     * <td align="center">if 1080p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">JPEG</td>
+     * <td style="text-align: center;">1920x1080 (1080p)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;">if 1080p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
-     * <td align="center">FULL</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">1920x1080 (1080p)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 1080p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">1920x1080 (1080p)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 1080p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">1280x720 (720)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 720p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">1280x720 (720)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 720p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">640x480 (480p)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 480p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">640x480 (480p)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 480p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">320x240 (240p)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 240p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">320x240 (240p)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 240p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">YUV_420_888</td>
-     * <td align="center">all output sizes available for FULL hardware level, up to the maximum video size</td>
-     * <td align="center">LIMITED</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">YUV_420_888</td>
+     * <td style="text-align: center;">all output sizes available for FULL hardware level, up to the maximum video size</td>
+     * <td style="text-align: center;">LIMITED</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">IMPLEMENTATION_DEFINED</td>
-     * <td align="center">same as YUV_420_888</td>
-     * <td align="center">Any</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">IMPLEMENTATION_DEFINED</td>
+     * <td style="text-align: center;">same as YUV_420_888</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * </tbody>
      * </table>
@@ -2987,66 +2987,66 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">Format</th>
-     * <th align="center">Size</th>
-     * <th align="center">Hardware Level</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">Format</th>
+     * <th style="text-align: center;">Size</th>
+     * <th style="text-align: center;">Hardware Level</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1)</td>
-     * <td align="center">Any</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#JPEG }</td>
+     * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="center">1920x1080 (1080p)</td>
-     * <td align="center">Any</td>
-     * <td align="center">if 1080p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#JPEG }</td>
+     * <td style="text-align: center;">1920x1080 (1080p)</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;">if 1080p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
-     * <td align="center">FULL</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="center">1920x1080 (1080p)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 1080p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: center;">1920x1080 (1080p)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 1080p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="center">1280x720 (720)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 720p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: center;">1280x720 (720)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 720p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="center">640x480 (480p)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 480p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: center;">640x480 (480p)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 480p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="center">320x240 (240p)</td>
-     * <td align="center">FULL</td>
-     * <td align="center">if 240p &lt;= activeArraySize</td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: center;">320x240 (240p)</td>
+     * <td style="text-align: center;">FULL</td>
+     * <td style="text-align: center;">if 240p &lt;= activeArraySize</td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
-     * <td align="center">all output sizes available for FULL hardware level, up to the maximum video size</td>
-     * <td align="center">LIMITED</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+     * <td style="text-align: center;">all output sizes available for FULL hardware level, up to the maximum video size</td>
+     * <td style="text-align: center;">LIMITED</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * <tr>
-     * <td align="center">{@link android.graphics.ImageFormat#PRIVATE }</td>
-     * <td align="center">same as YUV_420_888</td>
-     * <td align="center">Any</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+     * <td style="text-align: center;">same as YUV_420_888</td>
+     * <td style="text-align: center;">Any</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * </tbody>
      * </table>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3e1deb2..1a15596 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -990,18 +990,18 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center"></td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device auto exposure algorithm is disabled</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;"></td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device auto exposure algorithm is disabled</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1009,120 +1009,120 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device initiates AE scan</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values changing</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device initiates AE scan</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values changing</td>
      * </tr>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Camera device finishes AE scan</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Good values, not changing</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Camera device finishes AE scan</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Good values, not changing</td>
      * </tr>
      * <tr>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Camera device finishes AE scan</td>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Converged but too dark w/o flash</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Camera device finishes AE scan</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Converged but too dark w/o flash</td>
      * </tr>
      * <tr>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Camera device initiates AE scan</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values changing</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Camera device initiates AE scan</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values changing</td>
      * </tr>
      * <tr>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Camera device initiates AE scan</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values changing</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Camera device initiates AE scan</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values changing</td>
      * </tr>
      * <tr>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values not good after unlock</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values not good after unlock</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Values good after unlock</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Values good after unlock</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Exposure good, but too dark</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Exposure good, but too dark</td>
      * </tr>
      * <tr>
-     * <td align="center">PRECAPTURE</td>
-     * <td align="center">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Ready for high-quality capture</td>
+     * <td style="text-align: center;">PRECAPTURE</td>
+     * <td style="text-align: center;">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Ready for high-quality capture</td>
      * </tr>
      * <tr>
-     * <td align="center">PRECAPTURE</td>
-     * <td align="center">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Ready for high-quality capture</td>
+     * <td style="text-align: center;">PRECAPTURE</td>
+     * <td style="text-align: center;">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Ready for high-quality capture</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">aeLock is ON and aePrecaptureTrigger is START</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">aeLock is ON and aePrecaptureTrigger is START</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Precapture trigger is ignored when AE is already locked</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Precapture trigger is ignored when AE is already locked</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state (excluding LOCKED)</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START</td>
-     * <td align="center">PRECAPTURE</td>
-     * <td align="center">Start AE precapture metering sequence</td>
+     * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START</td>
+     * <td style="text-align: center;">PRECAPTURE</td>
+     * <td style="text-align: center;">Start AE precapture metering sequence</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state (excluding LOCKED)</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Currently active precapture metering sequence is canceled</td>
+     * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Currently active precapture metering sequence is canceled</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1138,54 +1138,54 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device finished AE scan</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Values are already good, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device finished AE scan</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Values are already good, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state (excluding LOCKED)</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state (excluding LOCKED)</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Converged after a precapture sequence, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Converged after a precapture sequence, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state (excluding LOCKED)</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state (excluding LOCKED)</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Converged after a precapture sequences canceled, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Converged after a precapture sequences canceled, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Camera device finished AE scan</td>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Camera device finished AE scan</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">FLASH_REQUIRED</td>
-     * <td align="center">Camera device finished AE scan</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Converged after a new scan, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">FLASH_REQUIRED</td>
+     * <td style="text-align: center;">Camera device finished AE scan</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Converged after a new scan, transient states are skipped by camera device.</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1413,18 +1413,18 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center"></td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Never changes</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;"></td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Never changes</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1432,66 +1432,66 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">ACTIVE_SCAN</td>
-     * <td align="center">Start AF sweep, Lens now moving</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">ACTIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF sweep, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">ACTIVE_SCAN</td>
-     * <td align="center">AF sweep done</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Focused, Lens now locked</td>
+     * <td style="text-align: center;">ACTIVE_SCAN</td>
+     * <td style="text-align: center;">AF sweep done</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Focused, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">ACTIVE_SCAN</td>
-     * <td align="center">AF sweep done</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Not focused, Lens now locked</td>
+     * <td style="text-align: center;">ACTIVE_SCAN</td>
+     * <td style="text-align: center;">AF sweep done</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Not focused, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">ACTIVE_SCAN</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Cancel/reset AF, Lens now locked</td>
+     * <td style="text-align: center;">ACTIVE_SCAN</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Cancel/reset AF, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Cancel/reset AF</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Cancel/reset AF</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">ACTIVE_SCAN</td>
-     * <td align="center">Start new sweep, Lens now moving</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">ACTIVE_SCAN</td>
+     * <td style="text-align: center;">Start new sweep, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Cancel/reset AF</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Cancel/reset AF</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">ACTIVE_SCAN</td>
-     * <td align="center">Start new sweep, Lens now moving</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">ACTIVE_SCAN</td>
+     * <td style="text-align: center;">Start new sweep, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
-     * <td align="center">Mode change</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center"></td>
+     * <td style="text-align: center;">Any state</td>
+     * <td style="text-align: center;">Mode change</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;"></td>
      * </tr>
      * </tbody>
      * </table>
@@ -1504,36 +1504,36 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Focus is already good or good after a scan, lens is now locked.</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Focus is already good or good after a scan, lens is now locked.</td>
      * </tr>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Focus failed after a scan, lens is now locked.</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Focus failed after a scan, lens is now locked.</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Focus is already good or good after a scan, lens is now locked.</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Focus is already good or good after a scan, lens is now locked.</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Focus is good after a scan, lens is not locked.</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Focus is good after a scan, lens is not locked.</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1541,102 +1541,102 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device initiates new scan</td>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Start AF scan, Lens now moving</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device initiates new scan</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF scan, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF state query, Lens now locked</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF state query, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Camera device completes current scan</td>
-     * <td align="center">PASSIVE_FOCUSED</td>
-     * <td align="center">End AF scan, Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Camera device completes current scan</td>
+     * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+     * <td style="text-align: center;">End AF scan, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Camera device fails current scan</td>
-     * <td align="center">PASSIVE_UNFOCUSED</td>
-     * <td align="center">End AF scan, Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Camera device fails current scan</td>
+     * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+     * <td style="text-align: center;">End AF scan, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Immediate transition, if focus is good. Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Immediate transition, if focus is good. Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Immediate transition, if focus is bad. Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Immediate transition, if focus is bad. Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Reset lens position, Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Reset lens position, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_FOCUSED</td>
-     * <td align="center">Camera device initiates new scan</td>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Start AF scan, Lens now moving</td>
+     * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+     * <td style="text-align: center;">Camera device initiates new scan</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF scan, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_UNFOCUSED</td>
-     * <td align="center">Camera device initiates new scan</td>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Start AF scan, Lens now moving</td>
+     * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+     * <td style="text-align: center;">Camera device initiates new scan</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF scan, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_FOCUSED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Immediate transition, lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Immediate transition, lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_UNFOCUSED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Immediate transition, lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Immediate transition, lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">No effect</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">No effect</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Restart AF scan</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Restart AF scan</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">No effect</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">No effect</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Restart AF scan</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Restart AF scan</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1644,102 +1644,102 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device initiates new scan</td>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Start AF scan, Lens now moving</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device initiates new scan</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF scan, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF state query, Lens now locked</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF state query, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Camera device completes current scan</td>
-     * <td align="center">PASSIVE_FOCUSED</td>
-     * <td align="center">End AF scan, Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Camera device completes current scan</td>
+     * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+     * <td style="text-align: center;">End AF scan, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Camera device fails current scan</td>
-     * <td align="center">PASSIVE_UNFOCUSED</td>
-     * <td align="center">End AF scan, Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Camera device fails current scan</td>
+     * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+     * <td style="text-align: center;">End AF scan, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Eventual transition once the focus is good. Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Eventual transition once the focus is good. Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Eventual transition if cannot find focus. Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Eventual transition if cannot find focus. Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Reset lens position, Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Reset lens position, Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_FOCUSED</td>
-     * <td align="center">Camera device initiates new scan</td>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Start AF scan, Lens now moving</td>
+     * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+     * <td style="text-align: center;">Camera device initiates new scan</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF scan, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_UNFOCUSED</td>
-     * <td align="center">Camera device initiates new scan</td>
-     * <td align="center">PASSIVE_SCAN</td>
-     * <td align="center">Start AF scan, Lens now moving</td>
+     * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+     * <td style="text-align: center;">Camera device initiates new scan</td>
+     * <td style="text-align: center;">PASSIVE_SCAN</td>
+     * <td style="text-align: center;">Start AF scan, Lens now moving</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_FOCUSED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">Immediate trans. Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Immediate trans. Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">PASSIVE_UNFOCUSED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">Immediate trans. Lens now locked</td>
+     * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">Immediate trans. Lens now locked</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">No effect</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">No effect</td>
      * </tr>
      * <tr>
-     * <td align="center">FOCUSED_LOCKED</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Restart AF scan</td>
+     * <td style="text-align: center;">FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Restart AF scan</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_TRIGGER</td>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">No effect</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_TRIGGER</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">No effect</td>
      * </tr>
      * <tr>
-     * <td align="center">NOT_FOCUSED_LOCKED</td>
-     * <td align="center">AF_CANCEL</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Restart AF scan</td>
+     * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+     * <td style="text-align: center;">AF_CANCEL</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Restart AF scan</td>
      * </tr>
      * </tbody>
      * </table>
@@ -1751,30 +1751,30 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">any state</td>
-     * <td align="center">CAF--&gt;AUTO mode switch</td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Mode switch without trigger, initial state must be INACTIVE</td>
+     * <td style="text-align: center;">any state</td>
+     * <td style="text-align: center;">CAF--&gt;AUTO mode switch</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Mode switch without trigger, initial state must be INACTIVE</td>
      * </tr>
      * <tr>
-     * <td align="center">any state</td>
-     * <td align="center">CAF--&gt;AUTO mode switch with AF_TRIGGER</td>
-     * <td align="center">trigger-reachable states from INACTIVE</td>
-     * <td align="center">Mode switch with trigger, INACTIVE is skipped</td>
+     * <td style="text-align: center;">any state</td>
+     * <td style="text-align: center;">CAF--&gt;AUTO mode switch with AF_TRIGGER</td>
+     * <td style="text-align: center;">trigger-reachable states from INACTIVE</td>
+     * <td style="text-align: center;">Mode switch with trigger, INACTIVE is skipped</td>
      * </tr>
      * <tr>
-     * <td align="center">any state</td>
-     * <td align="center">AUTO--&gt;CAF mode switch</td>
-     * <td align="center">passively reachable states from INACTIVE</td>
-     * <td align="center">Mode switch without trigger, passive transient state is skipped</td>
+     * <td style="text-align: center;">any state</td>
+     * <td style="text-align: center;">AUTO--&gt;CAF mode switch</td>
+     * <td style="text-align: center;">passively reachable states from INACTIVE</td>
+     * <td style="text-align: center;">Mode switch without trigger, passive transient state is skipped</td>
      * </tr>
      * </tbody>
      * </table>
@@ -2053,18 +2053,18 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center"></td>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device auto white balance algorithm is disabled</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;"></td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device auto white balance algorithm is disabled</td>
      * </tr>
      * </tbody>
      * </table>
@@ -2072,54 +2072,54 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device initiates AWB scan</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values changing</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device initiates AWB scan</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values changing</td>
      * </tr>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Camera device finishes AWB scan</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Good values, not changing</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Camera device finishes AWB scan</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Good values, not changing</td>
      * </tr>
      * <tr>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Camera device initiates AWB scan</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values changing</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Camera device initiates AWB scan</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values changing</td>
      * </tr>
      * <tr>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
-     * <td align="center">LOCKED</td>
-     * <td align="center">Values locked</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">Values locked</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
-     * <td align="center">SEARCHING</td>
-     * <td align="center">Values not good after unlock</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
+     * <td style="text-align: center;">SEARCHING</td>
+     * <td style="text-align: center;">Values not good after unlock</td>
      * </tr>
      * </tbody>
      * </table>
@@ -2132,24 +2132,24 @@
      * <table>
      * <thead>
      * <tr>
-     * <th align="center">State</th>
-     * <th align="center">Transition Cause</th>
-     * <th align="center">New State</th>
-     * <th align="center">Notes</th>
+     * <th style="text-align: center;">State</th>
+     * <th style="text-align: center;">Transition Cause</th>
+     * <th style="text-align: center;">New State</th>
+     * <th style="text-align: center;">Notes</th>
      * </tr>
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="center">INACTIVE</td>
-     * <td align="center">Camera device finished AWB scan</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Values are already good, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">INACTIVE</td>
+     * <td style="text-align: center;">Camera device finished AWB scan</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Values are already good, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">LOCKED</td>
-     * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
-     * <td align="center">CONVERGED</td>
-     * <td align="center">Values good after unlock, transient states are skipped by camera device.</td>
+     * <td style="text-align: center;">LOCKED</td>
+     * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
+     * <td style="text-align: center;">CONVERGED</td>
+     * <td style="text-align: center;">Values good after unlock, transient states are skipped by camera device.</td>
      * </tr>
      * </tbody>
      * </table>
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index 15e3ce2..61b24aa 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -47,4 +47,9 @@
      * @see SystemConfigManager#getEnabledComponentOverrides
      */
     List<ComponentName> getEnabledComponentOverrides(String packageName);
+
+    /**
+     * @see SystemConfigManager#getDefaultVrComponents
+     */
+    List<ComponentName> getDefaultVrComponents();
 }
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index cde2063..77843d9 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -147,4 +147,18 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Return the components that are enabled by default as VR mode listener services.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)
+    public List<ComponentName> getDefaultVrComponents() {
+        try {
+            return mInterface.getDefaultVrComponents();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return Collections.emptyList();
+    }
 }
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index acf4da6..2cd9f89 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -257,6 +257,13 @@
         return INSTALL_FAILED_CONTAINER_ERROR;
     }
 
+    if (fsync(fd) < 0) {
+        ALOGE("Coulnd't fsync temporary file name: %s: %s\n", localTmpFileName, strerror(errno));
+        close(fd);
+        unlink(localTmpFileName);
+        return INSTALL_FAILED_INTERNAL_ERROR;
+    }
+
     close(fd);
 
     // Set the modification time for this file to the ZIP's mod time.
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index d8ea0a5..2d6e8f5 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -13,8 +13,6 @@
         <option name="run-command" value="cmd window tracing level all" />
         <!-- set WM tracing to frame (avoid incomplete states) -->
         <option name="run-command" value="cmd window tracing frame" />
-        <!-- set Layer tracing buffer size to 50mb -->
-        <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 51200" />
         <!-- ensure lock screen mode is swipe -->
         <option name="run-command" value="locksettings set-disabled false" />
         <!-- restart launcher to activate TAPL -->
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
index a207bf1..fa186c3 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
@@ -304,13 +304,13 @@
                 for (int j = 0; j < NUM_EFFECTS; j++) {
                     effects[j] = new BassBoost(0, mSession);
                     effects[j].setControlStatusListener(mEffectListener);
-                    yield();
+                    this.yield();
                 }
                 for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
                     Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
                     effects[j].release();
                     effects[j] = null;
-                    yield();
+                    this.yield();
                 }
             }
             Log.w(TAG, "HammerReleaseTest ended");
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
index dcfe11a..5d91a2e 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
@@ -251,13 +251,13 @@
             for (int i = 0; i < NUM_ITERATIONS; i++) {
                 for (int j = 0; j < NUM_EFFECTS; j++) {
                     effects[j] = new Visualizer(mSession);
-                    yield();
+                    this.yield();
                 }
                 for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
                     Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
                     effects[j].release();
                     effects[j] = null;
-                    yield();
+                    this.yield();
                 }
             }
             Log.w(TAG, "HammerReleaseTest ended");
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index db54ae3..d4439f9 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -39,7 +39,6 @@
         android:layout_height="wrap_content"
         android:paddingStart="24dp"
         android:paddingEnd="24dp"
-        android:singleLine="true"
         android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt
new file mode 100644
index 0000000..96cc02f
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager
+
+import android.app.slice.Slice
+import android.credentials.ui.Entry
+import android.graphics.drawable.Icon
+
+/**
+ * UI representation for a credential entry used during the get credential flow.
+ *
+ * TODO: move to jetpack.
+ */
+class CredentialEntryUi(
+  val userName: CharSequence,
+  val displayName: CharSequence?,
+  val icon: Icon?,
+  // TODO: add last used.
+) {
+  companion object {
+    fun fromSlice(slice: Slice): CredentialEntryUi {
+      val items = slice.items
+
+      var title: String? = null
+      var subTitle: String? = null
+      var icon: Icon? = null
+
+      items.forEach {
+        if (it.hasHint(Entry.HINT_ICON)) {
+          icon = it.icon
+        } else if (it.hasHint(Entry.HINT_SUBTITLE)) {
+          subTitle = it.text.toString()
+        } else if (it.hasHint(Entry.HINT_TITLE)) {
+          title = it.text.toString()
+        }
+      }
+      // TODO: fail NPE more elegantly.
+      return CredentialEntryUi(title!!, subTitle, icon)
+    }
+  }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 46bf19c..8db547a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager
 
 import android.app.slice.Slice
@@ -9,11 +25,8 @@
 import android.credentials.ui.RequestInfo
 import android.graphics.drawable.Icon
 import android.os.Binder
-import com.android.credentialmanager.createflow.CreateOptionInfo
 import com.android.credentialmanager.createflow.CreatePasskeyUiState
 import com.android.credentialmanager.createflow.CreateScreenState
-import com.android.credentialmanager.createflow.ProviderInfo
-import com.android.credentialmanager.getflow.CredentialOptionInfo
 import com.android.credentialmanager.getflow.GetCredentialUiState
 import com.android.credentialmanager.getflow.GetScreenState
 
@@ -41,6 +54,39 @@
     ) ?: testProviderList()
   }
 
+  fun getCredentialInitialUiState(): GetCredentialUiState {
+    val providerList = GetFlowUtils.toProviderList(providerList, context)
+    return GetCredentialUiState(
+      providerList,
+      GetScreenState.CREDENTIAL_SELECTION,
+      providerList.first()
+    )
+  }
+
+  fun createPasskeyInitialUiState(): CreatePasskeyUiState {
+    val providerList = CreateFlowUtils.toProviderList(providerList, context)
+    return CreatePasskeyUiState(
+      providers = providerList,
+      currentScreenState = CreateScreenState.PASSKEY_INTRO,
+    )
+  }
+
+  companion object {
+    lateinit var repo: CredentialManagerRepo
+
+    fun setup(
+      context: Context,
+      intent: Intent,
+    ) {
+      repo = CredentialManagerRepo(context, intent)
+    }
+
+    fun getInstance(): CredentialManagerRepo {
+      return repo
+    }
+  }
+
+  // TODO: below are prototype functionalities. To be removed for productionization.
   private fun testProviderList(): List<ProviderData> {
     return listOf(
       ProviderData(
@@ -94,143 +140,4 @@
       slice
     )
   }
-
-  private fun getCredentialProviderList():
-    List<com.android.credentialmanager.getflow.ProviderInfo> {
-      return listOf(
-        com.android.credentialmanager.getflow.ProviderInfo(
-          icon = context.getDrawable(R.drawable.ic_passkey)!!,
-          name = "Google Password Manager",
-          appDomainName = "tribank.us",
-          credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
-          credentialOptions = listOf(
-            CredentialOptionInfo(
-              icon = context.getDrawable(R.drawable.ic_passkey)!!,
-              title = "Elisa Backett",
-              subtitle = "elisa.beckett@gmail.com",
-              id = "id-1",
-            ),
-            CredentialOptionInfo(
-              icon = context.getDrawable(R.drawable.ic_passkey)!!,
-              title = "Elisa Backett Work",
-              subtitle = "elisa.beckett.work@google.com",
-              id = "id-2",
-            ),
-          )
-        ),
-        com.android.credentialmanager.getflow.ProviderInfo(
-          icon = context.getDrawable(R.drawable.ic_passkey)!!,
-          name = "Lastpass",
-          appDomainName = "tribank.us",
-          credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
-          credentialOptions = listOf(
-            CredentialOptionInfo(
-              icon = context.getDrawable(R.drawable.ic_passkey)!!,
-              title = "Elisa Backett",
-              subtitle = "elisa.beckett@lastpass.com",
-              id = "id-1",
-            ),
-          )
-        ),
-        com.android.credentialmanager.getflow.ProviderInfo(
-          icon = context.getDrawable(R.drawable.ic_passkey)!!,
-          name = "Dashlane",
-          appDomainName = "tribank.us",
-          credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
-          credentialOptions = listOf(
-            CredentialOptionInfo(
-              icon = context.getDrawable(R.drawable.ic_passkey)!!,
-              title = "Elisa Backett",
-              subtitle = "elisa.beckett@dashlane.com",
-              id = "id-1",
-            ),
-          )
-        ),
-      )
-  }
-
-  private fun createCredentialProviderList(): List<ProviderInfo> {
-    return listOf(
-      ProviderInfo(
-        icon = context.getDrawable(R.drawable.ic_passkey)!!,
-        name = "Google Password Manager",
-        appDomainName = "tribank.us",
-        credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
-        createOptions = listOf(
-          CreateOptionInfo(
-            icon = context.getDrawable(R.drawable.ic_passkey)!!,
-            title = "Elisa Backett",
-            subtitle = "elisa.beckett@gmail.com",
-            id = "id-1",
-          ),
-          CreateOptionInfo(
-            icon = context.getDrawable(R.drawable.ic_passkey)!!,
-            title = "Elisa Backett Work",
-            subtitle = "elisa.beckett.work@google.com",
-            id = "id-2",
-          ),
-        )
-      ),
-      ProviderInfo(
-        icon = context.getDrawable(R.drawable.ic_passkey)!!,
-        name = "Lastpass",
-        appDomainName = "tribank.us",
-        credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
-        createOptions = listOf(
-          CreateOptionInfo(
-            icon = context.getDrawable(R.drawable.ic_passkey)!!,
-            title = "Elisa Backett",
-            subtitle = "elisa.beckett@lastpass.com",
-            id = "id-1",
-          ),
-        )
-      ),
-      ProviderInfo(
-        icon = context.getDrawable(R.drawable.ic_passkey)!!,
-        name = "Dashlane",
-        appDomainName = "tribank.us",
-        credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
-        createOptions = listOf(
-          CreateOptionInfo(
-            icon = context.getDrawable(R.drawable.ic_passkey)!!,
-            title = "Elisa Backett",
-            subtitle = "elisa.beckett@dashlane.com",
-            id = "id-1",
-          ),
-        )
-      ),
-    )
-  }
-
-  fun getCredentialInitialUiState(): GetCredentialUiState {
-    val providerList = getCredentialProviderList()
-    return GetCredentialUiState(
-      providerList,
-      GetScreenState.CREDENTIAL_SELECTION,
-      providerList.first()
-    )
-  }
-
-  fun createPasskeyInitialUiState(): CreatePasskeyUiState {
-    val providerList = createCredentialProviderList()
-    return CreatePasskeyUiState(
-      providers = providerList,
-      currentScreenState = CreateScreenState.PASSKEY_INTRO,
-    )
-  }
-
-  companion object {
-    lateinit var repo: CredentialManagerRepo
-
-    fun setup(
-      context: Context,
-      intent: Intent,
-    ) {
-      repo = CredentialManagerRepo(context, intent)
-    }
-
-    fun getInstance(): CredentialManagerRepo {
-      return repo
-    }
-  }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 98c824c..b538ae7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -1,5 +1,22 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager
 
+import android.credentials.ui.RequestInfo
 import android.os.Bundle
 import android.util.Log
 import androidx.activity.ComponentActivity
@@ -16,14 +33,20 @@
   override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState)
     CredentialManagerRepo.setup(this, intent)
-    val startDestination = intent.extras?.getString(
-      "start_destination",
-      "CREATE_PASSKEY"
-    ) ?: "CREATE_PASSKEY"
-
-    setContent {
-      CredentialSelectorTheme {
-        CredentialManagerBottomSheet(startDestination)
+    val requestInfo = intent.extras?.getParcelable<RequestInfo>(RequestInfo.EXTRA_REQUEST_INFO)
+    if (requestInfo != null) {
+      val requestType = requestInfo.type
+      setContent {
+        CredentialSelectorTheme {
+          CredentialManagerBottomSheet(requestType)
+        }
+      }
+    } else {
+      // TODO: prototype only code to be removed. In production should exit.
+      setContent {
+        CredentialSelectorTheme {
+          CredentialManagerBottomSheet(RequestInfo.TYPE_CREATE)
+        }
       }
     }
   }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
new file mode 100644
index 0000000..7159ab9
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager
+
+import android.content.Context
+import android.credentials.ui.Entry
+import android.credentials.ui.ProviderData
+import com.android.credentialmanager.createflow.CreateOptionInfo
+import com.android.credentialmanager.getflow.CredentialOptionInfo
+import com.android.credentialmanager.getflow.ProviderInfo
+
+/** Utility functions for converting CredentialManager data structures to or from UI formats. */
+class GetFlowUtils {
+  companion object {
+
+    fun toProviderList(
+      providerDataList: List<ProviderData>,
+      context: Context,
+    ): List<ProviderInfo> {
+      return providerDataList.map {
+        ProviderInfo(
+          // TODO: replace to extract from the service data structure when available
+          icon = context.getDrawable(R.drawable.ic_passkey)!!,
+          name = it.packageName,
+          appDomainName = "tribank.us",
+          credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
+          credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context)
+        )
+      }
+    }
+
+
+    /* From service data structure to UI credential entry list representation. */
+    private fun toCredentialOptionInfoList(
+      credentialEntries: List<Entry>,
+      context: Context,
+    ): List<CredentialOptionInfo> {
+      return credentialEntries.map {
+        val credentialEntryUi = CredentialEntryUi.fromSlice(it.slice)
+
+        // Consider directly move the UI object into the class.
+        return@map CredentialOptionInfo(
+          // TODO: remove fallbacks
+          icon = credentialEntryUi.icon?.loadDrawable(context)
+            ?: context.getDrawable(R.drawable.ic_passkey)!!,
+          title = credentialEntryUi.userName.toString(),
+          subtitle = credentialEntryUi.displayName?.toString() ?: "Unknown display name",
+          id = it.entryId,
+        )
+      }
+    }
+  }
+}
+
+class CreateFlowUtils {
+  companion object {
+
+    fun toProviderList(
+      providerDataList: List<ProviderData>,
+      context: Context,
+    ): List<com.android.credentialmanager.createflow.ProviderInfo> {
+      return providerDataList.map {
+        com.android.credentialmanager.createflow.ProviderInfo(
+          // TODO: replace to extract from the service data structure when available
+          icon = context.getDrawable(R.drawable.ic_passkey)!!,
+          name = it.packageName,
+          appDomainName = "tribank.us",
+          credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
+          createOptions = toCreationOptionInfoList(it.credentialEntries, context),
+        )
+      }
+    }
+
+    private fun toCreationOptionInfoList(
+      creationEntries: List<Entry>,
+      context: Context,
+    ): List<CreateOptionInfo> {
+      return creationEntries.map {
+        val saveEntryUi = SaveEntryUi.fromSlice(it.slice)
+
+        return@map CreateOptionInfo(
+          // TODO: remove fallbacks
+          icon = saveEntryUi.icon?.loadDrawable(context)
+            ?: context.getDrawable(R.drawable.ic_passkey)!!,
+          title = saveEntryUi.title.toString(),
+          subtitle = saveEntryUi.subTitle?.toString() ?: "Unknown subtitle",
+          id = it.entryId,
+        )
+      }
+    }
+  }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/SaveEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/SaveEntryUi.kt
new file mode 100644
index 0000000..2b63e1d
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/SaveEntryUi.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager
+
+import android.app.slice.Slice
+import android.credentials.ui.Entry
+import android.graphics.drawable.Icon
+
+/**
+ * UI representation for a save entry used during the create credential flow.
+ *
+ * TODO: move to jetpack.
+ */
+class SaveEntryUi(
+  val title: CharSequence,
+  val subTitle: CharSequence?,
+  val icon: Icon?,
+  // TODO: add
+) {
+  companion object {
+    fun fromSlice(slice: Slice): SaveEntryUi {
+      val items = slice.items
+
+      var title: String? = null
+      var subTitle: String? = null
+      var icon: Icon? = null
+
+      items.forEach {
+        if (it.hasHint(Entry.HINT_ICON)) {
+          icon = it.icon
+        } else if (it.hasHint(Entry.HINT_SUBTITLE)) {
+          subTitle = it.text.toString()
+        } else if (it.hasHint(Entry.HINT_TITLE)) {
+          title = it.text.toString()
+        }
+      }
+      // TODO: fail NPE more elegantly.
+      return SaveEntryUi(title!!, subTitle, icon)
+    }
+  }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
index 8bb80a1..b5e9fd00 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
@@ -1,5 +1,23 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager.common
 
+import android.credentials.ui.RequestInfo
+
 enum class DialogType {
   CREATE_PASSKEY,
   GET_CREDENTIALS,
@@ -8,10 +26,10 @@
 
   companion object {
     fun toDialogType(value: String): DialogType {
-      return try {
-        valueOf(value)
-      } catch (e: IllegalArgumentException) {
-        UNKNOWN
+      return when (value) {
+        RequestInfo.TYPE_GET -> GET_CREDENTIALS
+        RequestInfo.TYPE_CREATE -> CREATE_PASSKEY
+        else -> UNKNOWN
       }
     }
   }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 044688b..12f1846 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager.createflow
 
 import android.graphics.drawable.Drawable
@@ -14,7 +30,7 @@
   val icon: Drawable,
   val title: String,
   val subtitle: String,
-  val id: String,
+  val id: Int,
 )
 
 /** The name of the current screen. */
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
index 997519d..b61f465 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
@@ -222,7 +222,9 @@
   ) {
     Column() {
       TopAppBar(
-        title = { Text(text = stringResource(R.string.string_more_options), style = Typography.subtitle1) },
+        title = {
+          Text(text = stringResource(R.string.string_more_options), style = Typography.subtitle1)
+        },
         backgroundColor = lightBackgroundColor,
         elevation = 0.dp,
         navigationIcon =
@@ -343,7 +345,7 @@
 @Composable
 fun CreationSelectionCard(
   providerInfo: ProviderInfo,
-  onOptionSelected: (String) -> Unit,
+  onOptionSelected: (Int) -> Unit,
   onCancel: () -> Unit,
   multiProvider: Boolean,
   onMoreOptionSelected: (String) -> Unit,
@@ -414,7 +416,7 @@
 
 @ExperimentalMaterialApi
 @Composable
-fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (String) -> Unit) {
+fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (Int) -> Unit) {
   Chip(
     modifier = Modifier.fillMaxWidth(),
     onClick = {onOptionSelected(createOptionInfo.id)},
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
index 15300de..5b70f9d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager.createflow
 
 import android.util.Log
@@ -42,7 +58,7 @@
     )
   }
 
-  fun onCreateOptionSelected(createOptionId: String) {
+  fun onCreateOptionSelected(createOptionId: Int) {
     Log.d("Account Selector", "Option selected for creation: $createOptionId")
   }
 
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 1ca70ed..0b18822 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager.getflow
 
 import androidx.compose.foundation.Image
@@ -74,7 +90,7 @@
 @Composable
 fun CredentialSelectionCard(
   providerInfo: ProviderInfo,
-  onOptionSelected: (String) -> Unit,
+  onOptionSelected: (Int) -> Unit,
   onCancel: () -> Unit,
   multiProvider: Boolean,
   onMoreOptionSelected: () -> Unit,
@@ -149,7 +165,7 @@
 @Composable
 fun CredentialOptionRow(
     credentialOptionInfo: CredentialOptionInfo,
-    onOptionSelected: (String) -> Unit
+    onOptionSelected: (Int) -> Unit
 ) {
   Chip(
     modifier = Modifier.fillMaxWidth(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 06bcd7f..0fdd8ec 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager.getflow
 
 import android.util.Log
@@ -20,7 +36,7 @@
   var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
       private set
 
-  fun onCredentailSelected(credentialId: String) {
+  fun onCredentailSelected(credentialId: Int) {
     Log.d("Account Selector", "credential selected: $credentialId")
   }
 
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 867e9c2..acea8c9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 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.credentialmanager.getflow
 
 import android.graphics.drawable.Drawable
@@ -14,7 +30,7 @@
   val icon: Drawable,
   val title: String,
   val subtitle: String,
-  val id: String,
+  val id: Int,
 )
 
 /** The name of the current screen. */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
index 3885025..f762f6e 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
@@ -17,6 +17,9 @@
 package com.android.settingslib.spa.framework.common
 
 import android.app.Activity
+import android.util.Log
+
+private const val TAG = "SpaEnvironment"
 
 object SpaEnvironmentFactory {
     private var spaEnvironment: SpaEnvironment? = null
@@ -28,8 +31,10 @@
             return spaEnvironment!!
         }
         set(env: SpaEnvironment) {
-            if (spaEnvironment != null)
-                throw UnsupportedOperationException("Spa environment is already set")
+            if (spaEnvironment != null) {
+                Log.w(TAG, "Spa environment is already set, ignore the latter one.")
+                return
+            }
             spaEnvironment = env
         }
 }
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index c5bea2e..79677eea 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -4,6 +4,7 @@
         android:sharedUserId="android.uid.system">
 
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
 
     <application android:allowClearUserData="false"
                  android:label="@string/app_label"
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8efec67..3a25d85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -86,6 +86,7 @@
 import android.os.RemoteException;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.SystemConfigManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -110,12 +111,11 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.providers.settings.SettingsState.Setting;
-import com.android.server.SystemConfig;
-
-import com.google.android.collect.Sets;
 
 import libcore.util.HexEncoding;
 
+import com.google.android.collect.Sets;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
@@ -368,6 +368,8 @@
     // We have to call in the package manager with no lock held,
     private volatile IPackageManager mPackageManager;
 
+    private volatile SystemConfigManager mSysConfigManager;
+
     @GuardedBy("mLock")
     private boolean mSyncConfigDisabledUntilReboot;
 
@@ -397,6 +399,7 @@
         synchronized (mLock) {
             mUserManager = UserManager.get(getContext());
             mPackageManager = AppGlobals.getPackageManager();
+            mSysConfigManager = getContext().getSystemService(SystemConfigManager.class);
             mHandlerThread = new HandlerThread(LOG_TAG,
                     Process.THREAD_PRIORITY_BACKGROUND);
             mHandlerThread.start();
@@ -3875,8 +3878,7 @@
                     Setting currentSetting = secureSettings.getSettingLocked(
                             Settings.Secure.ENABLED_VR_LISTENERS);
                     if (currentSetting.isNull()) {
-                        ArraySet<ComponentName> l =
-                                SystemConfig.getInstance().getDefaultVrComponents();
+                        List<ComponentName> l = mSysConfigManager.getDefaultVrComponents();
 
                         if (l != null && !l.isEmpty()) {
                             StringBuilder b = new StringBuilder();
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index d90156d..8135aaa 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -241,4 +241,6 @@
     <string name="clock_title_bubble">Bubble</string>
     <!-- Name of the "Analog" clock face [CHAR LIMIT=15]-->
     <string name="clock_title_analog">Analog</string>
+    <!-- Title of bouncer when we want to authenticate before continuing with action. [CHAR LIMIT=NONE] -->
+    <string name="keyguard_unlock_to_continue">Unlock your device to continue</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c34db15..93ee151 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -67,7 +67,6 @@
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowManager;
-import android.widget.AdapterView;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -318,7 +317,8 @@
     }
 
     void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager,
-            UserSwitcherController userSwitcherController) {
+            UserSwitcherController userSwitcherController,
+            UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback) {
         if (mCurrentMode == mode) return;
         Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to "
                 + modeToString(mode));
@@ -330,7 +330,7 @@
                 mViewMode = new OneHandedViewMode();
                 break;
             case MODE_USER_SWITCHER:
-                mViewMode = new UserSwitcherViewMode();
+                mViewMode = new UserSwitcherViewMode(userSwitcherCallback);
                 break;
             default:
                 mViewMode = new DefaultViewMode();
@@ -864,6 +864,12 @@
         private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
                 this::setupUserSwitcher;
 
+        private UserSwitcherCallback mUserSwitcherCallback;
+
+        UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback) {
+            mUserSwitcherCallback = userSwitcherCallback;
+        }
+
         @Override
         public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
                 @NonNull KeyguardSecurityViewFlipper viewFlipper,
@@ -1040,34 +1046,25 @@
                 }
             };
 
-            if (adapter.getCount() < 2) {
-                // The drop down arrow is at index 1
-                ((LayerDrawable) mUserSwitcher.getBackground()).getDrawable(1).setAlpha(0);
-                anchor.setClickable(false);
-                return;
-            } else {
-                ((LayerDrawable) mUserSwitcher.getBackground()).getDrawable(1).setAlpha(255);
-            }
-
             anchor.setOnClickListener((v) -> {
                 if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
                 mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager);
                 mPopup.setAnchorView(anchor);
                 mPopup.setAdapter(adapter);
-                mPopup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-                        public void onItemClick(AdapterView parent, View view, int pos, long id) {
-                            if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
-                            if (!view.isEnabled()) return;
-
-                            // Subtract one for the header
-                            UserRecord user = adapter.getItem(pos - 1);
-                            if (!user.isCurrent) {
-                                adapter.onUserListItemClicked(user);
-                            }
-                            mPopup.dismiss();
-                            mPopup = null;
-                        }
-                    });
+                mPopup.setOnItemClickListener((parent, view, pos, id) -> {
+                    if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
+                    if (!view.isEnabled()) return;
+                    // Subtract one for the header
+                    UserRecord user = adapter.getItem(pos - 1);
+                    if (user.isManageUsers || user.isAddSupervisedUser) {
+                        mUserSwitcherCallback.showUnlockToContinueMessage();
+                    }
+                    if (!user.isCurrent) {
+                        adapter.onUserListItemClicked(user);
+                    }
+                    mPopup.dismiss();
+                    mPopup = null;
+                });
                 mPopup.show();
             });
         }
@@ -1122,6 +1119,10 @@
                 constraintSet.applyTo(mView);
             }
         }
+
+        interface UserSwitcherCallback {
+            void showUnlockToContinueMessage();
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index d448f40..bcd1a1e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -620,7 +620,9 @@
             mode = KeyguardSecurityContainer.MODE_ONE_HANDED;
         }
 
-        mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController);
+        mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController,
+                () -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue),
+                        null));
     }
 
     public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
index 9eb2c11..c9128e5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -109,12 +109,13 @@
             object : AnimatorListenerAdapter() {
                 override fun onAnimationEnd(animation: Animator) {
                     runningSecurityShiftAnimator = null
+                    if (shouldRestoreLayerType) {
+                        v.setLayerType(View.LAYER_TYPE_NONE, /* paint= */ null)
+                    }
                 }
             }
         )
 
-        var finishedFadingOutNonSecurityView = false
-
         runningSecurityShiftAnimator.addUpdateListener { animation: ValueAnimator ->
             val switchPoint = SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION
             val isFadingOut = animation.animatedFraction < switchPoint
@@ -153,6 +154,13 @@
                         startRect.right + currentTranslation,
                         startRect.bottom
                     )
+                } else {
+                    v.setLeftTopRightBottom(
+                        startRect.left,
+                        startRect.top,
+                        startRect.right,
+                        startRect.bottom
+                    )
                 }
             } else {
                 // And in again over the remaining (100-X)%.
@@ -175,32 +183,13 @@
                         endRect.right - translationRemaining,
                         endRect.bottom
                     )
-                }
-            }
-            if (animation.animatedFraction == 1.0f && shouldRestoreLayerType) {
-                v.setLayerType(View.LAYER_TYPE_NONE, /* paint= */ null)
-            }
-
-            // For views that are not the security view flipper, we do not want to apply
-            // an x translation animation. Instead, we want to fade out, move to final position and
-            // then fade in.
-            if (v !is KeyguardSecurityViewFlipper) {
-                // Opacity goes close to 0 but does not fully get to 0.
-                if (opacity - 0.001f < 0f) {
+                } else {
                     v.setLeftTopRightBottom(
                         endRect.left,
                         endRect.top,
                         endRect.right,
                         endRect.bottom
                     )
-                    finishedFadingOutNonSecurityView = true
-                } else if (!finishedFadingOutNonSecurityView) {
-                    v.setLeftTopRightBottom(
-                        startRect.left,
-                        startRect.top,
-                        startRect.right,
-                        startRect.bottom
-                    )
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 8f6c96a..7f08f86 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -105,10 +105,6 @@
      */
     public static final UnreleasedFlag MODERN_BOUNCER = new UnreleasedFlag(208);
 
-    /** Whether UserSwitcherActivity should use modern architecture. */
-    public static final ReleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
-            new ReleasedFlag(209, true);
-
     /**
      * Whether the user interactor and repository should use `UserSwitcherController`.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 01cd3e2..f663b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -19,7 +19,7 @@
 
 import android.content.Intent
 import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
@@ -67,19 +67,19 @@
      *
      * @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of
      * the affordance that was clicked
-     * @param animationController An optional controller for the activity-launch animation
+     * @param expandable An optional [Expandable] for the activity- or dialog-launch animation
      */
     fun onQuickAffordanceClicked(
         configKey: KClass<out KeyguardQuickAffordanceConfig>,
-        animationController: ActivityLaunchAnimator.Controller?,
+        expandable: Expandable?,
     ) {
         @Suppress("UNCHECKED_CAST") val config = registry.get(configKey as KClass<Nothing>)
-        when (val result = config.onQuickAffordanceClicked(animationController)) {
+        when (val result = config.onQuickAffordanceClicked(expandable)) {
             is KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity ->
                 launchQuickAffordance(
                     intent = result.intent,
                     canShowWhileLocked = result.canShowWhileLocked,
-                    animationController = animationController
+                    expandable = expandable,
                 )
             is KeyguardQuickAffordanceConfig.OnClickedResult.Handled -> Unit
         }
@@ -104,6 +104,7 @@
                 KeyguardQuickAffordanceModel.Visible(
                     configKey = configs[index]::class,
                     icon = visibleState.icon,
+                    toggle = visibleState.toggle,
                 )
             } else {
                 KeyguardQuickAffordanceModel.Hidden
@@ -114,7 +115,7 @@
     private fun launchQuickAffordance(
         intent: Intent,
         canShowWhileLocked: Boolean,
-        animationController: ActivityLaunchAnimator.Controller?,
+        expandable: Expandable?,
     ) {
         @LockPatternUtils.StrongAuthTracker.StrongAuthFlags
         val strongAuthFlags =
@@ -130,13 +131,13 @@
             activityStarter.postStartActivityDismissingKeyguard(
                 intent,
                 0 /* delay */,
-                animationController
+                expandable?.activityLaunchController(),
             )
         } else {
             activityStarter.startActivity(
                 intent,
                 true /* dismissShade */,
-                animationController,
+                expandable?.activityLaunchController(),
                 true /* showOverLockscreenWhenLocked */,
             )
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
index eb6bb92..e56b259 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
@@ -19,6 +19,7 @@
 
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
 import kotlin.reflect.KClass
 
 /**
@@ -35,5 +36,7 @@
         val configKey: KClass<out KeyguardQuickAffordanceConfig>,
         /** An icon for the affordance. */
         val icon: Icon,
+        /** The toggle state for the affordance. */
+        val toggle: KeyguardQuickAffordanceToggleState,
     ) : KeyguardQuickAffordanceModel()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 89604f0..8384260 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -20,7 +20,7 @@
 import android.content.Context
 import android.content.Intent
 import androidx.annotation.DrawableRes
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.ContentDescription
@@ -61,7 +61,7 @@
         }
 
     override fun onQuickAffordanceClicked(
-        animationController: ActivityLaunchAnimator.Controller?,
+        expandable: Expandable?,
     ): KeyguardQuickAffordanceConfig.OnClickedResult {
         return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
             intent =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 8e1c6b7..95027d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -18,8 +18,9 @@
 package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.content.Intent
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
 import kotlinx.coroutines.flow.Flow
 
 /** Defines interface that can act as data source for a single quick affordance model. */
@@ -27,9 +28,7 @@
 
     val state: Flow<State>
 
-    fun onQuickAffordanceClicked(
-        animationController: ActivityLaunchAnimator.Controller?
-    ): OnClickedResult
+    fun onQuickAffordanceClicked(expandable: Expandable?): OnClickedResult
 
     /**
      * Encapsulates the state of a "quick affordance" in the keyguard bottom area (for example, a
@@ -44,6 +43,9 @@
         data class Visible(
             /** An icon for the affordance. */
             val icon: Icon,
+            /** The toggle state for the affordance. */
+            val toggle: KeyguardQuickAffordanceToggleState =
+                KeyguardQuickAffordanceToggleState.NotSupported,
         ) : State()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index d97deaf..502a607 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -18,7 +18,7 @@
 package com.android.systemui.keyguard.domain.quickaffordance
 
 import com.android.systemui.R
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.ContentDescription
@@ -66,7 +66,7 @@
     }
 
     override fun onQuickAffordanceClicked(
-        animationController: ActivityLaunchAnimator.Controller?,
+        expandable: Expandable?,
     ): KeyguardQuickAffordanceConfig.OnClickedResult {
         return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
             intent = controller.intent,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 9196b09..a24a0d6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -23,7 +23,7 @@
 import android.service.quickaccesswallet.QuickAccessWalletClient
 import android.util.Log
 import com.android.systemui.R
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.ContentDescription
@@ -84,11 +84,11 @@
     }
 
     override fun onQuickAffordanceClicked(
-        animationController: ActivityLaunchAnimator.Controller?,
+        expandable: Expandable?,
     ): KeyguardQuickAffordanceConfig.OnClickedResult {
         walletController.startQuickAccessUiIntent(
             activityStarter,
-            animationController,
+            expandable?.activityLaunchController(),
             /* hasCard= */ true,
         )
         return KeyguardQuickAffordanceConfig.OnClickedResult.Handled
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt
new file mode 100644
index 0000000..55d38a4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 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.keyguard.shared.quickaffordance
+
+/** Enumerates all possible toggle states for a quick affordance on the lock-screen. */
+sealed class KeyguardQuickAffordanceToggleState {
+    /** Toggling is not supported. */
+    object NotSupported : KeyguardQuickAffordanceToggleState()
+    /** The quick affordance is on. */
+    object On : KeyguardQuickAffordanceToggleState()
+    /** The quick affordance is off. */
+    object Off : KeyguardQuickAffordanceToggleState()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 65b85c0..2c99ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -29,7 +29,7 @@
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.settingslib.Utils
 import com.android.systemui.R
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
@@ -238,14 +238,26 @@
 
         IconViewBinder.bind(viewModel.icon, view)
 
+        view.isActivated = viewModel.isActivated
         view.drawable.setTint(
             Utils.getColorAttrDefaultColor(
                 view.context,
-                com.android.internal.R.attr.textColorPrimary
+                if (viewModel.isActivated) {
+                    com.android.internal.R.attr.textColorPrimaryInverse
+                } else {
+                    com.android.internal.R.attr.textColorPrimary
+                },
             )
         )
         view.backgroundTintList =
-            Utils.getColorAttr(view.context, com.android.internal.R.attr.colorSurface)
+            Utils.getColorAttr(
+                view.context,
+                if (viewModel.isActivated) {
+                    com.android.internal.R.attr.colorAccentPrimary
+                } else {
+                    com.android.internal.R.attr.colorSurface
+                }
+            )
 
         view.isClickable = viewModel.isClickable
         if (viewModel.isClickable) {
@@ -268,7 +280,7 @@
                 viewModel.onClicked(
                     KeyguardQuickAffordanceViewModel.OnClickedParameters(
                         configKey = viewModel.configKey,
-                        animationController = ActivityLaunchAnimator.Controller.fromView(view),
+                        expandable = Expandable.fromView(view),
                     )
                 )
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 970ee4c..535ca72 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -119,10 +120,11 @@
                     onClicked = { parameters ->
                         quickAffordanceInteractor.onQuickAffordanceClicked(
                             configKey = parameters.configKey,
-                            animationController = parameters.animationController,
+                            expandable = parameters.expandable,
                         )
                     },
                     isClickable = isClickable,
+                    isActivated = toggle is KeyguardQuickAffordanceToggleState.On,
                 )
             is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel()
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
index 0971f13..bf598ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
 import kotlin.reflect.KClass
@@ -30,9 +30,10 @@
     val icon: Icon = Icon.Resource(res = 0, contentDescription = null),
     val onClicked: (OnClickedParameters) -> Unit = {},
     val isClickable: Boolean = false,
+    val isActivated: Boolean = false,
 ) {
     data class OnClickedParameters(
         val configKey: KClass<out KeyguardQuickAffordanceConfig>,
-        val animationController: ActivityLaunchAnimator.Controller?,
+        val expandable: Expandable?,
     )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 50a10bc..6da8c69 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -114,6 +114,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
 import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener;
@@ -211,6 +212,7 @@
     private final NotificationShadeDepthController mNotificationShadeDepthController;
     private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
     private final UserContextProvider mUserContextProvider;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final RegionSamplingHelper mRegionSamplingHelper;
     private final int mNavColorSampleMargin;
     private NavigationBarFrame mFrame;
@@ -451,6 +453,28 @@
                 }
             };
 
+    private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+            new WakefulnessLifecycle.Observer() {
+                private void notifyScreenStateChanged(boolean isScreenOn) {
+                    notifyNavigationBarScreenOn();
+                    mView.onScreenStateChanged(isScreenOn);
+                }
+
+                @Override
+                public void onStartedWakingUp() {
+                    notifyScreenStateChanged(true);
+                    if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) {
+                        mRegionSamplingHelper.start(mSamplingBounds);
+                    }
+                }
+
+                @Override
+                public void onFinishedGoingToSleep() {
+                    notifyScreenStateChanged(false);
+                    mRegionSamplingHelper.stop();
+                }
+            };
+
     @Inject
     NavigationBar(
             NavigationBarView navigationBarView,
@@ -491,7 +515,8 @@
             NavigationBarTransitions navigationBarTransitions,
             EdgeBackGestureHandler edgeBackGestureHandler,
             Optional<BackAnimation> backAnimation,
-            UserContextProvider userContextProvider) {
+            UserContextProvider userContextProvider,
+            WakefulnessLifecycle wakefulnessLifecycle) {
         super(navigationBarView);
         mFrame = navigationBarFrame;
         mContext = context;
@@ -529,6 +554,7 @@
         mTelecomManagerOptional = telecomManagerOptional;
         mInputMethodManager = inputMethodManager;
         mUserContextProvider = userContextProvider;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
 
         mNavColorSampleMargin = getResources()
                 .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
@@ -682,11 +708,10 @@
         prepareNavigationBarView();
         checkNavBarModes();
 
-        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Intent.ACTION_SCREEN_ON);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
         mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter,
                 Handler.getMain(), UserHandle.ALL);
+        mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
         notifyNavigationBarScreenOn();
 
         mOverviewProxyService.addCallback(mOverviewProxyListener);
@@ -737,6 +762,7 @@
         getBarTransitions().destroy();
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
         mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+        mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
         if (mOrientationHandle != null) {
             resetSecondaryHandle();
             getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
@@ -1619,19 +1645,6 @@
                 return;
             }
             String action = intent.getAction();
-            if (Intent.ACTION_SCREEN_OFF.equals(action)
-                    || Intent.ACTION_SCREEN_ON.equals(action)) {
-                notifyNavigationBarScreenOn();
-                boolean isScreenOn = Intent.ACTION_SCREEN_ON.equals(action);
-                mView.onScreenStateChanged(isScreenOn);
-                if (isScreenOn) {
-                    if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) {
-                        mRegionSamplingHelper.start(mSamplingBounds);
-                    }
-                } else {
-                    mRegionSamplingHelper.stop();
-                }
-            }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 // The accessibility settings may be different for the new user
                 updateAccessibilityStateFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 029cf68..3fd1aa7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -21,6 +21,7 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
 import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
 
 import android.content.ContentResolver;
@@ -141,7 +142,13 @@
     public void onConfigChanged(Configuration newConfig) {
         boolean isOldConfigTablet = mIsTablet;
         mIsTablet = isTablet(mContext);
+        boolean willApplyConfig = mConfigChanges.applyNewConfig(mContext.getResources());
         boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
+        // TODO(b/243765256): Disable this logging once b/243765256 is fixed.
+        Log.d(DEBUG_MISSING_GESTURE_TAG, "NavbarController: newConfig=" + newConfig
+                + " mTaskbarDelegate initialized=" + mTaskbarDelegate.isInitialized()
+                + " willApplyConfigToNavbars=" + willApplyConfig
+                + " navBarCount=" + mNavigationBars.size());
         if (mTaskbarDelegate.isInitialized()) {
             mTaskbarDelegate.onConfigurationChanged(newConfig);
         }
@@ -150,7 +157,7 @@
             return;
         }
 
-        if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+        if (willApplyConfig) {
             for (int i = 0; i < mNavigationBars.size(); i++) {
                 recreateNavigationBar(mNavigationBars.keyAt(i));
             }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index a8799c7..709467f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -113,7 +113,7 @@
     private static final int MAX_NUM_LOGGED_GESTURES = 10;
 
     static final boolean DEBUG_MISSING_GESTURE = false;
-    static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
+    public static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
 
     private ISystemGestureExclusionListener mGestureExclusionListener =
             new ISystemGestureExclusionListener.Stub() {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index fae0b50..1da866e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -46,6 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 
@@ -78,6 +79,7 @@
 
     private final PowerManager mPowerManager;
     private final WarningsUI mWarnings;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
     private InattentiveSleepWarningView mOverlayView;
     private final Configuration mLastConfiguration = new Configuration();
     private int mPlugType = 0;
@@ -107,11 +109,24 @@
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final CommandQueue mCommandQueue;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
+    private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+            new WakefulnessLifecycle.Observer() {
+                @Override
+                public void onStartedWakingUp() {
+                    mScreenOffTime = -1;
+                }
+
+                @Override
+                public void onFinishedGoingToSleep() {
+                    mScreenOffTime = SystemClock.elapsedRealtime();
+                }
+            };
 
     @Inject
     public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             WarningsUI warningsUI, EnhancedEstimates enhancedEstimates,
+            WakefulnessLifecycle wakefulnessLifecycle,
             PowerManager powerManager) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
@@ -120,6 +135,7 @@
         mWarnings = warningsUI;
         mEnhancedEstimates = enhancedEstimates;
         mPowerManager = powerManager;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
     }
 
     public void start() {
@@ -138,6 +154,7 @@
                 false, obs, UserHandle.USER_ALL);
         updateBatteryWarningLevels();
         mReceiver.init();
+        mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
 
         // Check to see if we need to let the user know that the phone previously shut down due
         // to the temperature being too high.
@@ -233,8 +250,6 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-            filter.addAction(Intent.ACTION_SCREEN_OFF);
-            filter.addAction(Intent.ACTION_SCREEN_ON);
             filter.addAction(Intent.ACTION_USER_SWITCHED);
             mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
             // Force get initial values. Relying on Sticky behavior until API for getting info.
@@ -317,10 +332,6 @@
                             plugged, bucket);
                 });
 
-            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                mScreenOffTime = SystemClock.elapsedRealtime();
-            } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
-                mScreenOffTime = -1;
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mWarnings.userSwitched();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 11d9555..d3c06f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -23,7 +23,6 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
 import com.android.settingslib.Utils
-import com.android.settingslib.drawable.UserIconDrawable
 import com.android.systemui.R
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
@@ -250,22 +249,19 @@
         status: UserSwitcherStatusModel.Enabled
     ): FooterActionsButtonViewModel {
         val icon = status.currentUserImage!!
-        val iconTint =
-            if (status.isGuestUser && icon !is UserIconDrawable) {
-                Utils.getColorAttrDefaultColor(context, android.R.attr.colorForeground)
-            } else {
-                null
-            }
 
         return FooterActionsButtonViewModel(
             id = R.id.multi_user_switch,
-            Icon.Loaded(
-                icon,
-                ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
-            ),
-            iconTint,
-            R.drawable.qs_footer_action_circle,
-            this::onUserSwitcherClicked,
+            icon =
+                Icon.Loaded(
+                    icon,
+                    ContentDescription.Loaded(
+                        userSwitcherContentDescription(status.currentUserName)
+                    ),
+                ),
+            iconTint = null,
+            background = R.drawable.qs_footer_action_circle,
+            onClick = this::onUserSwitcherClicked,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
index 950806d..ead3b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -49,7 +49,6 @@
     private final SwipeDismissHandler mSwipeDismissHandler;
     private final GestureDetector mSwipeDetector;
     private View mActionsContainer;
-    private View mActionsContainerBackground;
     private SwipeDismissCallbacks mCallbacks;
     private final DisplayMetrics mDisplayMetrics;
 
@@ -111,6 +110,9 @@
                     }
                 });
         mSwipeDetector.setIsLongpressEnabled(false);
+
+        mCallbacks = new SwipeDismissCallbacks() {
+        }; // default to unimplemented callbacks
     }
 
     public void setCallbacks(SwipeDismissCallbacks callbacks) {
@@ -119,16 +121,13 @@
 
     @Override
     public boolean onInterceptHoverEvent(MotionEvent event) {
-        if (mCallbacks != null) {
-            mCallbacks.onInteraction();
-        }
+        mCallbacks.onInteraction();
         return super.onInterceptHoverEvent(event);
     }
 
     @Override // View
     protected void onFinishInflate() {
         mActionsContainer = findViewById(R.id.actions_container);
-        mActionsContainerBackground = findViewById(R.id.actions_container_background);
     }
 
     @Override
@@ -186,6 +185,13 @@
         inoutInfo.touchableRegion.set(r);
     }
 
+    private int getBackgroundRight() {
+        // background expected to be null in testing.
+        // animation may have unexpected behavior if view is not present
+        View background = findViewById(R.id.actions_container_background);
+        return background == null ? 0 : background.getRight();
+    }
+
     /**
      * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not
      * met
@@ -213,8 +219,6 @@
             mGestureDetector = new GestureDetector(context, gestureListener);
             mDisplayMetrics = new DisplayMetrics();
             context.getDisplay().getRealMetrics(mDisplayMetrics);
-            mCallbacks = new SwipeDismissCallbacks() {
-            }; // default to unimplemented callbacks
         }
 
         @Override
@@ -230,7 +234,9 @@
                     return true;
                 }
                 if (isPastDismissThreshold()) {
-                    dismiss();
+                    ValueAnimator anim = createSwipeDismissAnimation();
+                    mCallbacks.onSwipeDismissInitiated(anim);
+                    dismiss(anim);
                 } else {
                     // if we've moved, but not past the threshold, start the return animation
                     if (DEBUG_DISMISS) {
@@ -295,10 +301,7 @@
         }
 
         void dismiss() {
-            float velocityPxPerMs = FloatingWindowUtil.dpToPx(mDisplayMetrics, VELOCITY_DP_PER_MS);
-            ValueAnimator anim = createSwipeDismissAnimation(velocityPxPerMs);
-            mCallbacks.onSwipeDismissInitiated(anim);
-            dismiss(anim);
+            dismiss(createSwipeDismissAnimation());
         }
 
         private void dismiss(ValueAnimator animator) {
@@ -323,6 +326,11 @@
             mDismissAnimation.start();
         }
 
+        private ValueAnimator createSwipeDismissAnimation() {
+            float velocityPxPerMs = FloatingWindowUtil.dpToPx(mDisplayMetrics, VELOCITY_DP_PER_MS);
+            return createSwipeDismissAnimation(velocityPxPerMs);
+        }
+
         private ValueAnimator createSwipeDismissAnimation(float velocity) {
             // velocity is measured in pixels per millisecond
             velocity = Math.min(3, Math.max(1, velocity));
@@ -337,7 +345,7 @@
             if (startX > 0 || (startX == 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
                 finalX = mDisplayMetrics.widthPixels;
             } else {
-                finalX = -1 * mActionsContainerBackground.getRight();
+                finalX = -1 * getBackgroundRight();
             }
             float distance = Math.abs(finalX - startX);
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 704e115..6d5121a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -28,6 +28,7 @@
 import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
 import static com.android.systemui.screenshot.LogConfig.logTag;
 import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT;
 
 import static java.util.Objects.requireNonNull;
 
@@ -331,9 +332,7 @@
             if (DEBUG_UI) {
                 Log.d(TAG, "Corner timeout hit");
             }
-            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT, 0,
-                    mPackageName);
-            ScreenshotController.this.dismissScreenshot(false);
+            dismissScreenshot(SCREENSHOT_INTERACTION_TIMEOUT);
         });
 
         mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -361,8 +360,7 @@
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (ClipboardOverlayController.COPY_OVERLAY_ACTION.equals(intent.getAction())) {
-                    mUiEventLogger.log(SCREENSHOT_DISMISSED_OTHER);
-                    dismissScreenshot(false);
+                    dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
                 }
             }
         };
@@ -410,24 +408,20 @@
     /**
      * Clears current screenshot
      */
-    void dismissScreenshot(boolean immediate) {
+    void dismissScreenshot(ScreenshotEvent event) {
         if (DEBUG_DISMISS) {
-            Log.d(TAG, "dismissScreenshot(immediate=" + immediate + ")");
+            Log.d(TAG, "dismissScreenshot");
         }
         // If we're already animating out, don't restart the animation
-        // (but do obey an immediate dismissal)
-        if (!immediate && mScreenshotView.isDismissing()) {
+        if (mScreenshotView.isDismissing()) {
             if (DEBUG_DISMISS) {
                 Log.v(TAG, "Already dismissing, ignoring duplicate command");
             }
             return;
         }
+        mUiEventLogger.log(event, 0, mPackageName);
         mScreenshotHandler.cancelTimeout();
-        if (immediate) {
-            finishDismiss();
-        } else {
-            mScreenshotView.animateDismissal();
-        }
+        mScreenshotView.animateDismissal();
     }
 
     boolean isPendingSharedTransition() {
@@ -500,7 +494,7 @@
                 if (DEBUG_INPUT) {
                     Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
                 }
-                dismissScreenshot(false);
+                dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
                 return true;
             }
             return false;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index a4a59ce..2176825 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -89,8 +89,7 @@
                     Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
                 }
                 if (!mScreenshot.isPendingSharedTransition()) {
-                    mUiEventLogger.log(SCREENSHOT_DISMISSED_OTHER);
-                    mScreenshot.dismissScreenshot(false);
+                    mScreenshot.dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index c290ce2..184dc25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -189,7 +189,6 @@
     protected NotificationPresenter mPresenter;
     protected ContentObserver mLockscreenSettingsObserver;
     protected ContentObserver mSettingsObserver;
-    private boolean mHideSilentNotificationsOnLockscreen;
 
     @Inject
     public NotificationLockscreenUserManagerImpl(Context context,
@@ -266,12 +265,6 @@
                 UserHandle.USER_ALL);
 
         mContext.getContentResolver().registerContentObserver(
-                mSecureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
-                true,
-                mLockscreenSettingsObserver,
-                UserHandle.USER_ALL);
-
-        mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
                 mSettingsObserver);
 
@@ -340,9 +333,6 @@
         final boolean allowedByDpm = (dpmFlags
                 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
 
-        mHideSilentNotificationsOnLockscreen = mSecureSettings.getIntForUser(
-                Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1, mCurrentUserId) == 0;
-
         setShowLockscreenNotifications(show && allowedByDpm);
 
         if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
index 6f41425..9a7610d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
@@ -114,7 +114,18 @@
      */
     public void unbindHeadsUpView(NotificationEntry entry) {
         abortBindCallback(entry);
-        mStage.getStageParams(entry).markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP);
+
+        // params may be null if the notification was already removed from the collection but we let
+        // it stick around during a launch animation. In this case, the heads up view has already
+        // been unbound, so we don't need to unbind it.
+        // TODO(b/253081345): Change this back to getStageParams and remove null check.
+        RowContentBindParams params = mStage.tryGetStageParams(entry);
+        if (params == null) {
+            mLogger.entryBindStageParamsNullOnUnbind(entry);
+            return;
+        }
+
+        params.markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP);
         mLogger.entryContentViewMarkedFreeable(entry);
         mStage.requestRebind(entry, e -> mLogger.entryUnbound(e));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
index d1feaa0..5dbec8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
@@ -47,6 +47,14 @@
             "start unbinding heads up entry $str1 "
         })
     }
+
+    fun entryBindStageParamsNullOnUnbind(entry: NotificationEntry) {
+        buffer.log(TAG, INFO, {
+            str1 = entry.logKey
+        }, {
+            "heads up entry bind stage params null on unbind $str1 "
+        })
+    }
 }
 
 private const val TAG = "HeadsUpViewBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
index 7c41800..d626c18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
@@ -64,7 +65,7 @@
      * Get the stage parameters for the entry. Clients should use this to modify how the stage
      * handles the notification content.
      */
-    public final Params getStageParams(@NonNull NotificationEntry entry) {
+    public final @NonNull Params getStageParams(@NonNull NotificationEntry entry) {
         Params params = mContentParams.get(entry);
         if (params == null) {
             // TODO: This should throw an exception but there are some cases of re-entrant calls
@@ -79,6 +80,17 @@
         return params;
     }
 
+    // TODO(b/253081345): Remove this method.
+    /**
+     * Get the stage parameters for the entry, or null if there are no stage parameters for the
+     * entry.
+     *
+     * @see #getStageParams(NotificationEntry)
+     */
+    public final @Nullable Params tryGetStageParams(@NonNull NotificationEntry entry) {
+        return mContentParams.get(entry);
+    }
+
     /**
      * Create a params entry for the notification for this stage.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
index 5b2d695..2f0ebf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
@@ -35,8 +35,8 @@
     protected val controller: UserSwitcherController,
 ) : BaseAdapter() {
 
-    protected open val users: ArrayList<UserRecord>
-        get() = controller.users
+    protected open val users: List<UserRecord>
+        get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted }
 
     init {
         controller.addAdapter(WeakReference(this))
@@ -112,6 +112,7 @@
                     item.isGuest,
                     item.isAddSupervisedUser,
                     isTablet,
+                    item.isManageUsers,
                 )
             return checkNotNull(context.getDrawable(iconRes))
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 494a4bb..c150654 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -53,6 +53,7 @@
 import com.android.systemui.util.ViewController;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.inject.Inject;
 
@@ -456,7 +457,7 @@
         }
 
         void refreshUserOrder() {
-            ArrayList<UserRecord> users = super.getUsers();
+            List<UserRecord> users = super.getUsers();
             mUsersOrdered = new ArrayList<>(users.size());
             for (int i = 0; i < users.size(); i++) {
                 UserRecord record = users.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
index af39eee..935fc7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
@@ -249,7 +249,7 @@
 
     override fun startActivity(intent: Intent) {
         if (useInteractor) {
-            activityStarter.startActivity(intent, /* dismissShade= */ false)
+            activityStarter.startActivity(intent, /* dismissShade= */ true)
         } else {
             _oldImpl.startActivity(intent)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
index 46d2f3a..c294c37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
@@ -49,6 +49,7 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.users.UserCreatingDialog;
 import com.android.systemui.GuestResetOrExitSessionReceiver;
 import com.android.systemui.GuestResumeSessionReceiver;
@@ -399,6 +400,16 @@
                 records.add(userRecord);
             }
 
+            if (canManageUsers()) {
+                records.add(LegacyUserDataHelper.createRecord(
+                        mContext,
+                        KeyguardUpdateMonitor.getCurrentUser(),
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+                        /* isRestricted= */ false,
+                        /* isSwitchToEnabled= */ true
+                ));
+            }
+
             mUiExecutor.execute(() -> {
                 if (records != null) {
                     mUsers = records;
@@ -438,6 +449,14 @@
                 && mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY);
     }
 
+    @VisibleForTesting
+    boolean canManageUsers() {
+        UserInfo currentUser = mUserTracker.getUserInfo();
+        return mUserSwitcherEnabled
+                && ((currentUser != null && currentUser.isAdmin())
+                || mAddUsersFromLockScreen.getValue());
+    }
+
     private boolean createIsRestricted() {
         return !mAddUsersFromLockScreen.getValue();
     }
@@ -525,6 +544,8 @@
             showAddUserDialog(dialogShower);
         } else if (record.isAddSupervisedUser) {
             startSupervisedUserActivity();
+        } else if (record.isManageUsers) {
+            startActivity(new Intent(Settings.ACTION_USER_SETTINGS));
         } else {
             onUserListItemClicked(record.info.id, record, dialogShower);
         }
@@ -984,7 +1005,7 @@
 
     @Override
     public void startActivity(Intent intent) {
-        mActivityStarter.startActivity(intent, true);
+        mActivityStarter.startActivity(intent, /* dismissShade= */ true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index 108ab43..7f1195b 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -16,426 +16,41 @@
 
 package com.android.systemui.user
 
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.LayerDrawable
 import android.os.Bundle
-import android.os.UserManager
-import android.provider.Settings
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.MotionEvent
 import android.view.View
-import android.view.ViewGroup
-import android.widget.AdapterView
-import android.widget.ArrayAdapter
-import android.widget.ImageView
-import android.widget.TextView
-import android.window.OnBackInvokedCallback
-import android.window.OnBackInvokedDispatcher
 import androidx.activity.ComponentActivity
-import androidx.constraintlayout.helper.widget.Flow
 import androidx.lifecycle.ViewModelProvider
-import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.util.UserIcons
-import com.android.settingslib.Utils
-import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
-import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.BaseUserSwitcherAdapter
-import com.android.systemui.statusbar.policy.UserSwitcherController
-import com.android.systemui.user.data.source.UserRecord
 import com.android.systemui.user.ui.binder.UserSwitcherViewBinder
 import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
 import dagger.Lazy
 import javax.inject.Inject
-import kotlin.math.ceil
-
-private const val USER_VIEW = "user_view"
 
 /** Support a fullscreen user switcher */
 open class UserSwitcherActivity
 @Inject
 constructor(
-    private val userSwitcherController: UserSwitcherController,
-    private val broadcastDispatcher: BroadcastDispatcher,
     private val falsingCollector: FalsingCollector,
-    private val falsingManager: FalsingManager,
-    private val userManager: UserManager,
-    private val userTracker: UserTracker,
-    private val flags: FeatureFlags,
     private val viewModelFactory: Lazy<UserSwitcherViewModel.Factory>,
 ) : ComponentActivity() {
 
-    private lateinit var parent: UserSwitcherRootView
-    private lateinit var broadcastReceiver: BroadcastReceiver
-    private var popupMenu: UserSwitcherPopupMenu? = null
-    private lateinit var addButton: View
-    private var addUserRecords = mutableListOf<UserRecord>()
-    private val onBackCallback = OnBackInvokedCallback { finish() }
-    private val userSwitchedCallback: UserTracker.Callback =
-        object : UserTracker.Callback {
-            override fun onUserChanged(newUser: Int, userContext: Context) {
-                finish()
-            }
-        }
-    // When the add users options become available, insert another option to manage users
-    private val manageUserRecord =
-        UserRecord(
-            null /* info */,
-            null /* picture */,
-            false /* isGuest */,
-            false /* isCurrent */,
-            false /* isAddUser */,
-            false /* isRestricted */,
-            false /* isSwitchToEnabled */,
-            false /* isAddSupervisedUser */
-        )
-
-    private val adapter: UserAdapter by lazy { UserAdapter() }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        createActivity()
-    }
-
-    @VisibleForTesting
-    fun createActivity() {
         setContentView(R.layout.user_switcher_fullscreen)
         window.decorView.systemUiVisibility =
             (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
                 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
-        if (isUsingModernArchitecture()) {
-            Log.d(TAG, "Using modern architecture.")
-            val viewModel =
-                ViewModelProvider(this, viewModelFactory.get())[UserSwitcherViewModel::class.java]
-            UserSwitcherViewBinder.bind(
-                view = requireViewById(R.id.user_switcher_root),
-                viewModel = viewModel,
-                lifecycleOwner = this,
-                layoutInflater = layoutInflater,
-                falsingCollector = falsingCollector,
-                onFinish = this::finish,
-            )
-            return
-        } else {
-            Log.d(TAG, "Not using modern architecture.")
-        }
-
-        parent = requireViewById<UserSwitcherRootView>(R.id.user_switcher_root)
-
-        parent.touchHandler =
-            object : Gefingerpoken {
-                override fun onTouchEvent(ev: MotionEvent?): Boolean {
-                    falsingCollector.onTouchEvent(ev)
-                    return false
-                }
-            }
-
-        requireViewById<View>(R.id.cancel).apply { setOnClickListener { _ -> finish() } }
-
-        addButton =
-            requireViewById<View>(R.id.add).apply { setOnClickListener { _ -> showPopupMenu() } }
-
-        onBackInvokedDispatcher.registerOnBackInvokedCallback(
-            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
-            onBackCallback
+        val viewModel =
+            ViewModelProvider(this, viewModelFactory.get())[UserSwitcherViewModel::class.java]
+        UserSwitcherViewBinder.bind(
+            view = requireViewById(R.id.user_switcher_root),
+            viewModel = viewModel,
+            lifecycleOwner = this,
+            layoutInflater = layoutInflater,
+            falsingCollector = falsingCollector,
+            onFinish = this::finish,
         )
-
-        userSwitcherController.init(parent)
-        initBroadcastReceiver()
-
-        parent.post { buildUserViews() }
-        userTracker.addCallback(userSwitchedCallback, mainExecutor)
-    }
-
-    private fun showPopupMenu() {
-        val items = mutableListOf<UserRecord>()
-        addUserRecords.forEach { items.add(it) }
-
-        var popupMenuAdapter =
-            ItemAdapter(
-                this,
-                R.layout.user_switcher_fullscreen_popup_item,
-                layoutInflater,
-                { item: UserRecord -> adapter.getName(this@UserSwitcherActivity, item, true) },
-                { item: UserRecord ->
-                    adapter.findUserIcon(item, true).mutate().apply {
-                        setTint(
-                            resources.getColor(
-                                R.color.user_switcher_fullscreen_popup_item_tint,
-                                getTheme()
-                            )
-                        )
-                    }
-                }
-            )
-        popupMenuAdapter.addAll(items)
-
-        popupMenu =
-            UserSwitcherPopupMenu(this).apply {
-                setAnchorView(addButton)
-                setAdapter(popupMenuAdapter)
-                setOnItemClickListener { parent: AdapterView<*>, view: View, pos: Int, id: Long ->
-                    if (falsingManager.isFalseTap(LOW_PENALTY) || !view.isEnabled()) {
-                        return@setOnItemClickListener
-                    }
-                    // -1 for the header
-                    val item = popupMenuAdapter.getItem(pos - 1)
-                    if (item == manageUserRecord) {
-                        val i = Intent().setAction(Settings.ACTION_USER_SETTINGS)
-                        this@UserSwitcherActivity.startActivity(i)
-                    } else {
-                        adapter.onUserListItemClicked(item)
-                    }
-
-                    dismiss()
-                    popupMenu = null
-
-                    if (!item.isAddUser) {
-                        this@UserSwitcherActivity.finish()
-                    }
-                }
-
-                show()
-            }
-    }
-
-    private fun buildUserViews() {
-        var count = 0
-        var start = 0
-        for (i in 0 until parent.getChildCount()) {
-            if (parent.getChildAt(i).getTag() == USER_VIEW) {
-                if (count == 0) start = i
-                count++
-            }
-        }
-        parent.removeViews(start, count)
-        addUserRecords.clear()
-        val flow = requireViewById<Flow>(R.id.flow)
-        val totalWidth = parent.width
-        val userViewCount = adapter.getTotalUserViews()
-        val maxColumns = getMaxColumns(userViewCount)
-        val horizontalGap =
-            resources.getDimensionPixelSize(R.dimen.user_switcher_fullscreen_horizontal_gap)
-        val totalWidthOfHorizontalGap = (maxColumns - 1) * horizontalGap
-        val maxWidgetDiameter = (totalWidth - totalWidthOfHorizontalGap) / maxColumns
-
-        flow.setMaxElementsWrap(maxColumns)
-
-        for (i in 0 until adapter.getCount()) {
-            val item = adapter.getItem(i)
-            if (adapter.doNotRenderUserView(item)) {
-                addUserRecords.add(item)
-            } else {
-                val userView = adapter.getView(i, null, parent)
-                userView.requireViewById<ImageView>(R.id.user_switcher_icon).apply {
-                    val lp = layoutParams
-                    if (maxWidgetDiameter < lp.width) {
-                        lp.width = maxWidgetDiameter
-                        lp.height = maxWidgetDiameter
-                        layoutParams = lp
-                    }
-                }
-
-                userView.setId(View.generateViewId())
-                parent.addView(userView)
-
-                // Views must have an id and a parent in order for Flow to lay them out
-                flow.addView(userView)
-
-                userView.setOnClickListener { v ->
-                    if (falsingManager.isFalseTap(LOW_PENALTY) || !v.isEnabled()) {
-                        return@setOnClickListener
-                    }
-
-                    if (!item.isCurrent || item.isGuest) {
-                        adapter.onUserListItemClicked(item)
-                    }
-                }
-            }
-        }
-
-        if (!addUserRecords.isEmpty()) {
-            addUserRecords.add(manageUserRecord)
-            addButton.visibility = View.VISIBLE
-        } else {
-            addButton.visibility = View.GONE
-        }
-    }
-
-    override fun onBackPressed() {
-        if (isUsingModernArchitecture()) {
-            return super.onBackPressed()
-        }
-
-        finish()
-    }
-
-    override fun onDestroy() {
-        super.onDestroy()
-        if (isUsingModernArchitecture()) {
-            return
-        }
-        destroyActivity()
-    }
-
-    @VisibleForTesting
-    fun destroyActivity() {
-        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackCallback)
-        broadcastDispatcher.unregisterReceiver(broadcastReceiver)
-        userTracker.removeCallback(userSwitchedCallback)
-    }
-
-    private fun initBroadcastReceiver() {
-        broadcastReceiver =
-            object : BroadcastReceiver() {
-                override fun onReceive(context: Context, intent: Intent) {
-                    val action = intent.getAction()
-                    if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                        finish()
-                    }
-                }
-            }
-
-        val filter = IntentFilter()
-        filter.addAction(Intent.ACTION_SCREEN_OFF)
-        broadcastDispatcher.registerReceiver(broadcastReceiver, filter)
-    }
-
-    @VisibleForTesting
-    fun getMaxColumns(userCount: Int): Int {
-        return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt()
-    }
-
-    private fun isUsingModernArchitecture(): Boolean {
-        return flags.isEnabled(Flags.MODERN_USER_SWITCHER_ACTIVITY)
-    }
-
-    /** Provides views to populate the option menu. */
-    private class ItemAdapter(
-        val parentContext: Context,
-        val resource: Int,
-        val layoutInflater: LayoutInflater,
-        val textGetter: (UserRecord) -> String,
-        val iconGetter: (UserRecord) -> Drawable
-    ) : ArrayAdapter<UserRecord>(parentContext, resource) {
-
-        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
-            val item = getItem(position)
-            val view = convertView ?: layoutInflater.inflate(resource, parent, false)
-
-            view.requireViewById<ImageView>(R.id.icon).apply { setImageDrawable(iconGetter(item)) }
-            view.requireViewById<TextView>(R.id.text).apply { setText(textGetter(item)) }
-
-            return view
-        }
-    }
-
-    private inner class UserAdapter : BaseUserSwitcherAdapter(userSwitcherController) {
-        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
-            val item = getItem(position)
-            var view = convertView as ViewGroup?
-            if (view == null) {
-                view =
-                    layoutInflater.inflate(R.layout.user_switcher_fullscreen_item, parent, false)
-                        as ViewGroup
-            }
-            (view.getChildAt(0) as ImageView).apply { setImageDrawable(getDrawable(item)) }
-            (view.getChildAt(1) as TextView).apply { setText(getName(getContext(), item)) }
-
-            view.setEnabled(item.isSwitchToEnabled)
-            UserSwitcherController.setSelectableAlpha(view)
-            view.setTag(USER_VIEW)
-            return view
-        }
-
-        override fun getName(context: Context, item: UserRecord, isTablet: Boolean): String {
-            return if (item == manageUserRecord) {
-                getString(R.string.manage_users)
-            } else {
-                super.getName(context, item, isTablet)
-            }
-        }
-
-        fun findUserIcon(item: UserRecord, isTablet: Boolean = false): Drawable {
-            if (item == manageUserRecord) {
-                return getDrawable(R.drawable.ic_manage_users)
-            }
-            if (item.info == null) {
-                return getIconDrawable(this@UserSwitcherActivity, item, isTablet)
-            }
-            val userIcon = userManager.getUserIcon(item.info.id)
-            if (userIcon != null) {
-                return BitmapDrawable(userIcon)
-            }
-            return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
-        }
-
-        fun getTotalUserViews(): Int {
-            return users.count { item -> !doNotRenderUserView(item) }
-        }
-
-        fun doNotRenderUserView(item: UserRecord): Boolean {
-            return item.isAddUser || item.isAddSupervisedUser || item.isGuest && item.info == null
-        }
-
-        private fun getDrawable(item: UserRecord): Drawable {
-            var drawable =
-                if (item.isGuest) {
-                    getDrawable(R.drawable.ic_account_circle)
-                } else {
-                    findUserIcon(item)
-                }
-            drawable.mutate()
-
-            if (!item.isCurrent && !item.isSwitchToEnabled) {
-                drawable.setTint(
-                    resources.getColor(
-                        R.color.kg_user_switcher_restricted_avatar_icon_color,
-                        getTheme()
-                    )
-                )
-            }
-
-            val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate() as LayerDrawable
-            if (item == userSwitcherController.currentUserRecord) {
-                (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
-                    val stroke =
-                        resources.getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
-                    val color =
-                        Utils.getColorAttrDefaultColor(
-                            this@UserSwitcherActivity,
-                            com.android.internal.R.attr.colorAccentPrimary
-                        )
-
-                    setStroke(stroke, color)
-                }
-            }
-
-            ld.setDrawableByLayerId(R.id.user_avatar, drawable)
-            return ld
-        }
-
-        override fun notifyDataSetChanged() {
-            super.notifyDataSetChanged()
-            buildUserViews()
-        }
-    }
-
-    companion object {
-        private const val TAG = "UserSwitcherActivity"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
index 9370286..d4fb563 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
@@ -47,6 +47,9 @@
      * If not disabled, this is `null`.
      */
     @JvmField val enforcedAdmin: RestrictedLockUtils.EnforcedAdmin? = null,
+
+    /** Whether this record is to go to the Settings page to manage users. */
+    @JvmField val isManageUsers: Boolean = false
 ) {
     /** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */
     fun copyWithIsCurrent(isCurrent: Boolean): UserRecord {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
index 1b4746a..dc004f3 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
@@ -82,6 +82,15 @@
         )
     }
 
+    fun canManageUsers(
+        repository: UserRepository,
+        isUserSwitcherEnabled: Boolean,
+        isAddUsersFromLockScreenEnabled: Boolean,
+    ): Boolean {
+        return isUserSwitcherEnabled &&
+            (repository.getSelectedUserInfo().isAdmin || isAddUsersFromLockScreenEnabled)
+    }
+
     /**
      * Returns `true` if the current user is allowed to add users to the device; `false` otherwise.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 142a328..ba5a82a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -102,6 +102,7 @@
     interface UserCallback {
         /** Returns `true` if this callback can be cleaned-up. */
         fun isEvictable(): Boolean = false
+
         /** Notifies that the state of users on the device has changed. */
         fun onUserStateChanged()
     }
@@ -164,10 +165,11 @@
         get() =
             if (isNewImpl) {
                 combine(
+                    repository.selectedUserInfo,
                     repository.userInfos,
                     repository.userSwitcherSettings,
                     keyguardInteractor.isKeyguardShowing,
-                ) { userInfos, settings, isDeviceLocked ->
+                ) { _, userInfos, settings, isDeviceLocked ->
                     buildList {
                         val hasGuestUser = userInfos.any { it.isGuest }
                         if (
@@ -183,35 +185,45 @@
                             add(UserActionModel.ENTER_GUEST_MODE)
                         }
 
-                        if (isDeviceLocked && !settings.isAddUsersFromLockscreen) {
+                        if (!isDeviceLocked || settings.isAddUsersFromLockscreen) {
                             // The device is locked and our setting to allow actions that add users
                             // from the lock-screen is not enabled. The guest action from above is
                             // always allowed, even when the device is locked, but the various "add
                             // user" actions below are not. We can finish building the list here.
-                            return@buildList
+
+                            val canCreateUsers =
+                                UserActionsUtil.canCreateUser(
+                                    manager,
+                                    repository,
+                                    settings.isUserSwitcherEnabled,
+                                    settings.isAddUsersFromLockscreen,
+                                )
+
+                            if (canCreateUsers) {
+                                add(UserActionModel.ADD_USER)
+                            }
+
+                            if (
+                                UserActionsUtil.canCreateSupervisedUser(
+                                    manager,
+                                    repository,
+                                    settings.isUserSwitcherEnabled,
+                                    settings.isAddUsersFromLockscreen,
+                                    supervisedUserPackageName,
+                                )
+                            ) {
+                                add(UserActionModel.ADD_SUPERVISED_USER)
+                            }
                         }
 
                         if (
-                            UserActionsUtil.canCreateUser(
-                                manager,
+                            UserActionsUtil.canManageUsers(
                                 repository,
                                 settings.isUserSwitcherEnabled,
                                 settings.isAddUsersFromLockscreen,
                             )
                         ) {
-                            add(UserActionModel.ADD_USER)
-                        }
-
-                        if (
-                            UserActionsUtil.canCreateSupervisedUser(
-                                manager,
-                                repository,
-                                settings.isUserSwitcherEnabled,
-                                settings.isAddUsersFromLockscreen,
-                                supervisedUserPackageName,
-                            )
-                        ) {
-                            add(UserActionModel.ADD_SUPERVISED_USER)
+                            add(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
                         }
                     }
                 }
@@ -264,7 +276,10 @@
                                 toRecord(
                                     action = it,
                                     selectedUserId = selectedUserInfo.id,
-                                    isAddFromLockscreenEnabled = settings.isAddUsersFromLockscreen,
+                                    isRestricted =
+                                        it != UserActionModel.ENTER_GUEST_MODE &&
+                                            it != UserActionModel.NAVIGATE_TO_USER_MANAGEMENT &&
+                                            !settings.isAddUsersFromLockscreen,
                                 )
                             }
                     )
@@ -482,12 +497,12 @@
                             .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
                             .setPackage(supervisedUserPackageName)
                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
-                        /* dismissShade= */ false,
+                        /* dismissShade= */ true,
                     )
                 UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
                     activityStarter.startActivity(
                         Intent(Settings.ACTION_USER_SETTINGS),
-                        /* dismissShade= */ false,
+                        /* dismissShade= */ true,
                     )
             }
         } else {
@@ -575,20 +590,13 @@
     private suspend fun toRecord(
         action: UserActionModel,
         selectedUserId: Int,
-        isAddFromLockscreenEnabled: Boolean,
+        isRestricted: Boolean,
     ): UserRecord {
         return LegacyUserDataHelper.createRecord(
             context = applicationContext,
             selectedUserId = selectedUserId,
             actionType = action,
-            isRestricted =
-                if (action == UserActionModel.ENTER_GUEST_MODE) {
-                    // Entering guest mode is never restricted, so it's allowed to happen from the
-                    // lockscreen even if the "add from lockscreen" system setting is off.
-                    false
-                } else {
-                    !isAddFromLockscreenEnabled
-                },
+            isRestricted = isRestricted,
             isSwitchToEnabled =
                 canSwitchUsers(selectedUserId) &&
                     // If the user is auto-created is must not be currently resetting.
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
index 137de15..03a7470 100644
--- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
@@ -80,6 +80,7 @@
                     context = context,
                     selectedUserId = selectedUserId,
                 ),
+            isManageUsers = actionType == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
         )
     }
 
@@ -90,6 +91,7 @@
             record.isAddUser -> UserActionModel.ADD_USER
             record.isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER
             record.isGuest -> UserActionModel.ENTER_GUEST_MODE
+            record.isManageUsers -> UserActionModel.NAVIGATE_TO_USER_MANAGEMENT
             else -> error("Not a known action: $record")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
index 15fdc35..e74232d 100644
--- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
@@ -22,7 +22,6 @@
 import androidx.annotation.StringRes
 import com.android.systemui.R
 import com.android.systemui.user.data.source.UserRecord
-import kotlin.math.ceil
 
 /**
  * Defines utility functions for helping with legacy UI code for users.
@@ -33,16 +32,6 @@
  */
 object LegacyUserUiHelper {
 
-    /** Returns the maximum number of columns for user items in the user switcher. */
-    fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
-        // TODO(b/243844097): remove this once we remove the old user switcher implementation.
-        return if (userCount < 5) {
-            4
-        } else {
-            ceil(userCount / 2.0).toInt()
-        }
-    }
-
     @JvmStatic
     @DrawableRes
     fun getUserSwitcherActionIconResourceId(
@@ -50,6 +39,7 @@
         isGuest: Boolean,
         isAddSupervisedUser: Boolean,
         isTablet: Boolean = false,
+        isManageUsers: Boolean,
     ): Int {
         return if (isAddUser && isTablet) {
             R.drawable.ic_account_circle_filled
@@ -59,6 +49,8 @@
             R.drawable.ic_account_circle
         } else if (isAddSupervisedUser) {
             R.drawable.ic_add_supervised_user
+        } else if (isManageUsers) {
+            R.drawable.ic_manage_users
         } else {
             R.drawable.ic_avatar_user
         }
@@ -85,6 +77,7 @@
                         isAddUser = record.isAddUser,
                         isAddSupervisedUser = record.isAddSupervisedUser,
                         isTablet = isTablet,
+                        isManageUsers = record.isManageUsers,
                     )
                 )
         }
@@ -114,8 +107,9 @@
         isAddUser: Boolean,
         isAddSupervisedUser: Boolean,
         isTablet: Boolean = false,
+        isManageUsers: Boolean,
     ): Int {
-        check(isGuest || isAddUser || isAddSupervisedUser)
+        check(isGuest || isAddUser || isAddSupervisedUser || isManageUsers)
 
         return when {
             isGuest && isGuestUserAutoCreated && isGuestUserResetting ->
@@ -125,6 +119,7 @@
             isGuest -> com.android.internal.R.string.guest_name
             isAddUser -> com.android.settingslib.R.string.user_add_user
             isAddSupervisedUser -> R.string.add_user_supervised
+            isManageUsers -> R.string.manage_users
             else -> error("This should never happen!")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index 5b83df7..219dae2 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -19,7 +19,6 @@
 
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
-import com.android.systemui.R
 import com.android.systemui.common.ui.drawable.CircularDrawable
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -30,6 +29,7 @@
 import com.android.systemui.user.shared.model.UserActionModel
 import com.android.systemui.user.shared.model.UserModel
 import javax.inject.Inject
+import kotlin.math.ceil
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
@@ -52,8 +52,7 @@
         userInteractor.users.map { models -> models.map { user -> toViewModel(user) } }
 
     /** The maximum number of columns that the user selection grid should use. */
-    val maximumUserColumns: Flow<Int> =
-        users.map { LegacyUserUiHelper.getMaxUserSwitcherItemColumns(it.size) }
+    val maximumUserColumns: Flow<Int> = users.map { getMaxUserSwitcherItemColumns(it.size) }
 
     private val _isMenuVisible = MutableStateFlow(false)
     /**
@@ -118,6 +117,15 @@
         _isMenuVisible.value = false
     }
 
+    /** Returns the maximum number of columns for user items in the user switcher. */
+    private fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
+        return if (userCount < 5) {
+            4
+        } else {
+            ceil(userCount / 2.0).toInt()
+        }
+    }
+
     private fun createFinishRequestedFlow(): Flow<Boolean> {
         var mostRecentSelectedUserId: Int? = null
         var mostRecentIsInteractive: Boolean? = null
@@ -171,27 +179,23 @@
         return UserActionViewModel(
             viewKey = model.ordinal.toLong(),
             iconResourceId =
-                if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
-                    R.drawable.ic_manage_users
-                } else {
-                    LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
-                        isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
-                        isAddUser = model == UserActionModel.ADD_USER,
-                        isGuest = model == UserActionModel.ENTER_GUEST_MODE,
-                    )
-                },
+                LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
+                    isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+                    isAddUser = model == UserActionModel.ADD_USER,
+                    isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+                    isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+                    isTablet = true,
+                ),
             textResourceId =
-                if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
-                    R.string.manage_users
-                } else {
-                    LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
-                        isGuest = model == UserActionModel.ENTER_GUEST_MODE,
-                        isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated,
-                        isGuestUserResetting = guestUserInteractor.isGuestUserResetting,
-                        isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
-                        isAddUser = model == UserActionModel.ADD_USER,
-                    )
-                },
+                LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
+                    isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+                    isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated,
+                    isGuestUserResetting = guestUserInteractor.isGuestUserResetting,
+                    isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+                    isAddUser = model == UserActionModel.ADD_USER,
+                    isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+                    isTablet = true,
+                ),
             onClicked = {
                 userInteractor.executeAction(action = model)
                 // We don't finish because we want to show a dialog over the full-screen UI and
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index c6ebaa8..48e8239 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -221,15 +221,17 @@
     public void onResourcesUpdate_callsThroughOnRotationChange() {
         // Rotation is the same, shouldn't cause an update
         mKeyguardSecurityContainerController.updateResources();
-        verify(mView, never()).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+        verify(mView, never()).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+                eq(mUserSwitcherController),
+                any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
 
         // Update rotation. Should trigger update
         mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
 
         mKeyguardSecurityContainerController.updateResources();
-        verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+        verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+                eq(mUserSwitcherController),
+                any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
     }
 
     private void touchDown() {
@@ -263,8 +265,9 @@
                 .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
 
         mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
-        verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+        verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+                eq(mUserSwitcherController),
+                any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
     }
 
     @Test
@@ -275,8 +278,9 @@
                 .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
 
         mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
-        verify(mView).initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+        verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager),
+                eq(mUserSwitcherController),
+                any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
     }
 
     @Test
@@ -285,8 +289,26 @@
         setupGetSecurityView();
 
         mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
-        verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+        verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+                eq(mUserSwitcherController),
+                any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+    }
+
+    @Test
+    public void addUserSwitcherCallback() {
+        ArgumentCaptor<KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback>
+                captor = ArgumentCaptor.forClass(
+                KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class);
+
+        setupGetSecurityView();
+
+        mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
+        verify(mView).initMode(anyInt(), any(GlobalSettings.class), any(FalsingManager.class),
+                any(UserSwitcherController.class),
+                captor.capture());
+        captor.getValue().showUnlockToContinueMessage();
+        verify(mKeyguardPasswordViewControllerMock).showMessage(
+                getContext().getString(R.string.keyguard_unlock_to_continue), null);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 52f8825..82d3ca7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -119,7 +119,7 @@
         int systemBarInsetAmount = 0;
 
         mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+                mUserSwitcherController, () -> {});
 
         Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
         Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -141,7 +141,7 @@
         int systemBarInsetAmount = paddingBottom + 1;
 
         mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+                mUserSwitcherController, () -> {});
 
         Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
         Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -158,9 +158,10 @@
     @Test
     public void testDefaultViewMode() {
         mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+                mUserSwitcherController, () -> {
+                });
         mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+                mUserSwitcherController, () -> {});
         ConstraintSet.Constraint viewFlipperConstraint =
                 getViewConstraint(mSecurityViewFlipper.getId());
         assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
@@ -377,7 +378,7 @@
     private void setupUserSwitcher() {
         when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
         mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
-                mGlobalSettings, mFalsingManager, mUserSwitcherController);
+                mGlobalSettings, mFalsingManager, mUserSwitcherController, () -> {});
     }
 
     private ArrayList<UserRecord> buildUserRecords(int count) {
@@ -387,7 +388,8 @@
                     0 /* flags */);
             users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */,
                     false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */,
-                    false /* isAddSupervisedUser */, null /* enforcedAdmin */));
+                    false /* isAddSupervisedUser */, null /* enforcedAdmin */,
+                    false /* isManageUsers */));
         }
         return users;
     }
@@ -395,7 +397,7 @@
     private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
         int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
         mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
-                mUserSwitcherController);
+                mUserSwitcherController, () -> {});
     }
 
     /** Get the ConstraintLayout constraint of the view. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index d52612b..f2ae7a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -35,6 +35,8 @@
 import android.view.WindowManager
 import android.widget.ScrollView
 import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.R
@@ -143,6 +145,35 @@
     }
 
     @Test
+    fun testDismissesOnFocusLoss_hidesKeyboardWhenVisible() {
+        val container = initializeFingerprintContainer(
+            authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+        )
+        waitForIdleSync()
+
+        val requestID = authContainer?.requestId ?: 0L
+
+        // Simulate keyboard was shown on the credential view
+        val windowInsetsController = container.windowInsetsController
+        spyOn(windowInsetsController)
+        spyOn(container.rootWindowInsets)
+        doReturn(true).`when`(container.rootWindowInsets).isVisible(WindowInsets.Type.ime())
+
+        container.onWindowFocusChanged(false)
+        waitForIdleSync()
+
+        // Expect hiding IME request will be invoked when dismissing the view
+        verify(windowInsetsController)?.hide(WindowInsets.Type.ime())
+
+        verify(callback).onDismissed(
+            eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
+            eq<ByteArray?>(null), /* credentialAttestation */
+            eq(requestID)
+        )
+        assertThat(container.parent).isNull()
+    }
+
+    @Test
     fun testActionAuthenticated_sendsDismissedAuthenticated() {
         val container = initializeFingerprintContainer()
         container.mBiometricCallback.onAction(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index b6d7559..b4d5464 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -12,20 +12,20 @@
  * 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.keyguard.domain.usecase
+package com.android.systemui.keyguard.domain.interactor
 
 import android.content.Intent
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
@@ -195,6 +195,7 @@
     @Mock private lateinit var userTracker: UserTracker
     @Mock private lateinit var activityStarter: ActivityStarter
     @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+    @Mock private lateinit var expandable: Expandable
 
     private lateinit var underTest: KeyguardQuickAffordanceInteractor
 
@@ -208,6 +209,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        whenever(expandable.activityLaunchController()).thenReturn(animationController)
 
         homeControls = object : FakeKeyguardQuickAffordanceConfig() {}
         underTest =
@@ -259,7 +261,7 @@
 
         underTest.onQuickAffordanceClicked(
             configKey = homeControls::class,
-            animationController = animationController,
+            expandable = expandable,
         )
 
         if (startActivity) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 1dd919a..65fd6e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -12,9 +12,10 @@
  * 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.keyguard.domain.usecase
+package com.android.systemui.keyguard.domain.interactor
 
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
@@ -22,13 +23,12 @@
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -103,6 +103,7 @@
         homeControls.setState(
             KeyguardQuickAffordanceConfig.State.Visible(
                 icon = ICON,
+                toggle = KeyguardQuickAffordanceToggleState.On,
             )
         )
 
@@ -123,6 +124,7 @@
         assertThat(visibleModel.icon).isEqualTo(ICON)
         assertThat(visibleModel.icon.contentDescription)
             .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
+        assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.On)
         job.cancel()
     }
 
@@ -152,6 +154,7 @@
         assertThat(visibleModel.icon).isEqualTo(ICON)
         assertThat(visibleModel.icon.contentDescription)
             .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
+        assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.NotSupported)
         job.cancel()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
index 6ea1daa..e99c139 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
@@ -17,7 +17,7 @@
 
 package com.android.systemui.keyguard.domain.quickaffordance
 
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -40,7 +40,7 @@
     override val state: Flow<KeyguardQuickAffordanceConfig.State> = _state
 
     override fun onQuickAffordanceClicked(
-        animationController: ActivityLaunchAnimator.Controller?,
+        expandable: Expandable?,
     ): OnClickedResult {
         return onClickedResult
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index dede4ec..a809f05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.dagger.ControlsComponent
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
@@ -44,7 +44,7 @@
 class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
 
     @Mock private lateinit var component: ControlsComponent
-    @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+    @Mock private lateinit var expandable: Expandable
 
     private lateinit var underTest: HomeControlsKeyguardQuickAffordanceConfig
 
@@ -103,7 +103,7 @@
     fun `onQuickAffordanceClicked - canShowWhileLockedSetting is true`() = runBlockingTest {
         whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
 
-        val onClickedResult = underTest.onQuickAffordanceClicked(animationController)
+        val onClickedResult = underTest.onQuickAffordanceClicked(expandable)
 
         assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java)
         assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isTrue()
@@ -113,7 +113,7 @@
     fun `onQuickAffordanceClicked - canShowWhileLockedSetting is false`() = runBlockingTest {
         whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
 
-        val onClickedResult = underTest.onQuickAffordanceClicked(animationController)
+        val onClickedResult = underTest.onQuickAffordanceClicked(expandable)
 
         assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java)
         assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 0a4478f..98dc4c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -24,11 +24,13 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.android.systemui.wallet.controller.QuickAccessWalletController
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
@@ -40,7 +42,6 @@
 import org.junit.runners.JUnit4
 import org.mockito.Mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -135,8 +136,11 @@
     @Test
     fun onQuickAffordanceClicked() {
         val animationController: ActivityLaunchAnimator.Controller = mock()
+        val expandable: Expandable = mock {
+            whenever(this.activityLaunchController()).thenReturn(animationController)
+        }
 
-        assertThat(underTest.onQuickAffordanceClicked(animationController))
+        assertThat(underTest.onQuickAffordanceClicked(expandable))
             .isEqualTo(KeyguardQuickAffordanceConfig.OnClickedResult.Handled)
         verify(walletController)
             .startQuickAccessUiIntent(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 96544e7..d674c89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -20,7 +20,7 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.doze.util.BurnInHelperWrapper
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -31,6 +31,7 @@
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -59,7 +60,7 @@
 @RunWith(JUnit4::class)
 class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
 
-    @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+    @Mock private lateinit var expandable: Expandable
     @Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
     @Mock private lateinit var lockPatternUtils: LockPatternUtils
     @Mock private lateinit var keyguardStateController: KeyguardStateController
@@ -130,6 +131,7 @@
             TestConfig(
                 isVisible = true,
                 isClickable = true,
+                isActivated = true,
                 icon = mock(),
                 canShowWhileLocked = false,
                 intent = Intent("action"),
@@ -505,6 +507,12 @@
                 }
                 KeyguardQuickAffordanceConfig.State.Visible(
                     icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
+                    toggle =
+                        when (testConfig.isActivated) {
+                            true -> KeyguardQuickAffordanceToggleState.On
+                            false -> KeyguardQuickAffordanceToggleState.Off
+                            null -> KeyguardQuickAffordanceToggleState.NotSupported
+                        }
                 )
             } else {
                 KeyguardQuickAffordanceConfig.State.Hidden
@@ -521,12 +529,13 @@
         checkNotNull(viewModel)
         assertThat(viewModel.isVisible).isEqualTo(testConfig.isVisible)
         assertThat(viewModel.isClickable).isEqualTo(testConfig.isClickable)
+        assertThat(viewModel.isActivated).isEqualTo(testConfig.isActivated)
         if (testConfig.isVisible) {
             assertThat(viewModel.icon).isEqualTo(testConfig.icon)
             viewModel.onClicked.invoke(
                 KeyguardQuickAffordanceViewModel.OnClickedParameters(
                     configKey = configKey,
-                    animationController = animationController,
+                    expandable = expandable,
                 )
             )
             if (testConfig.intent != null) {
@@ -542,6 +551,7 @@
     private data class TestConfig(
         val isVisible: Boolean,
         val isClickable: Boolean = false,
+        val isActivated: Boolean = false,
         val icon: Icon? = null,
         val canShowWhileLocked: Boolean = false,
         val intent: Intent? = null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 0e9d279..6adce7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -80,6 +80,7 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
 import com.android.systemui.navigationbar.buttons.DeadZone;
@@ -197,6 +198,8 @@
     @Mock
     private UserContextProvider mUserContextProvider;
     @Mock
+    private WakefulnessLifecycle mWakefulnessLifecycle;
+    @Mock
     private Resources mResources;
     private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
     private DeviceConfigProxyFake mDeviceConfigProxyFake = new DeviceConfigProxyFake();
@@ -474,7 +477,8 @@
                 mNavigationBarTransitions,
                 mEdgeBackGestureHandler,
                 Optional.of(mock(BackAnimation.class)),
-                mUserContextProvider));
+                mUserContextProvider,
+                mWakefulnessLifecycle));
     }
 
     private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 4e9b232..c377c37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -46,6 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.power.PowerUI.WarningsUI;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -84,6 +85,7 @@
     private PowerUI mPowerUI;
     @Mock private EnhancedEstimates mEnhancedEstimates;
     @Mock private PowerManager mPowerManager;
+    @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock private IThermalService mThermalServiceMock;
     private IThermalEventListener mUsbThermalEventListener;
     private IThermalEventListener mSkinThermalEventListener;
@@ -680,7 +682,7 @@
     private void createPowerUi() {
         mPowerUI = new PowerUI(
                 mContext, mBroadcastDispatcher, mCommandQueue, mCentralSurfacesOptionalLazy,
-                mMockWarnings, mEnhancedEstimates, mPowerManager);
+                mMockWarnings, mEnhancedEstimates, mWakefulnessLifecycle, mPowerManager);
         mPowerUI.mThermalService = mThermalServiceMock;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 2a4996f..760bb9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -192,16 +192,6 @@
         // UserManager change.
         assertThat(iconTint()).isNull()
 
-        // Trigger a user info change: there should now be a tint.
-        userInfoController.updateInfo { userAccount = "doe" }
-        assertThat(iconTint())
-            .isEqualTo(
-                Utils.getColorAttrDefaultColor(
-                    context,
-                    android.R.attr.colorForeground,
-                )
-            )
-
         // Make sure we don't tint the icon if it is a user image (and not the default image), even
         // in guest mode.
         userInfoController.updateInfo { this.picture = mock<UserIconDrawable>() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
new file mode 100644
index 0000000..c6ce51a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 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.screenshot;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class DraggableConstraintLayoutTest extends SysuiTestCase {
+
+    @Mock
+    DraggableConstraintLayout.SwipeDismissCallbacks mCallbacks;
+
+    private DraggableConstraintLayout mDraggableConstraintLayout;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDraggableConstraintLayout = new DraggableConstraintLayout(mContext, null, 0);
+    }
+
+    @Test
+    public void test_dismissDoesNotCallSwipeInitiated() {
+        mDraggableConstraintLayout.setCallbacks(mCallbacks);
+
+        mDraggableConstraintLayout.dismiss();
+
+        verify(mCallbacks, never()).onSwipeDismissInitiated(any());
+    }
+
+    @Test
+    public void test_onTouchCallsOnInteraction() {
+        mDraggableConstraintLayout.setCallbacks(mCallbacks);
+
+        mDraggableConstraintLayout.onInterceptTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+
+        verify(mCallbacks).onInteraction();
+    }
+
+    @Test
+    public void test_callbacksNotSet() {
+        // just test that it doesn't throw an NPE
+        mDraggableConstraintLayout.onInterceptTouchEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+        mDraggableConstraintLayout.onInterceptHoverEvent(
+                MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0));
+        mDraggableConstraintLayout.dismiss();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
index 3f641df..ca65987 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
@@ -91,6 +91,8 @@
         verifyNoMoreInteractions(mLogger);
         clearInvocations(mLogger);
 
+        when(mBindStage.tryGetStageParams(eq(mEntry))).thenReturn(new RowContentBindParams());
+
         mViewBinder.unbindHeadsUpView(mEntry);
         verify(mLogger).entryContentViewMarkedFreeable(eq(mEntry));
         verifyNoMoreInteractions(mLogger);
@@ -139,6 +141,8 @@
         verifyNoMoreInteractions(mLogger);
         clearInvocations(mLogger);
 
+        when(mBindStage.tryGetStageParams(eq(mEntry))).thenReturn(new RowContentBindParams());
+
         mViewBinder.unbindHeadsUpView(mEntry);
         verify(mLogger).currentOngoingBindingAborted(eq(mEntry));
         verify(mLogger).entryContentViewMarkedFreeable(eq(mEntry));
@@ -150,4 +154,30 @@
         verifyNoMoreInteractions(mLogger);
         clearInvocations(mLogger);
     }
+
+    @Test
+    public void testLoggingForLateUnbindFlow() {
+        AtomicReference<NotifBindPipeline.BindCallback> callback = new AtomicReference<>();
+        when(mBindStage.requestRebind(any(), any())).then(i -> {
+            callback.set(i.getArgument(1));
+            return new CancellationSignal();
+        });
+
+        mViewBinder.bindHeadsUpView(mEntry, null);
+        verify(mLogger).startBindingHun(eq(mEntry));
+        verifyNoMoreInteractions(mLogger);
+        clearInvocations(mLogger);
+
+        callback.get().onBindFinished(mEntry);
+        verify(mLogger).entryBoundSuccessfully(eq(mEntry));
+        verifyNoMoreInteractions(mLogger);
+        clearInvocations(mLogger);
+
+        when(mBindStage.tryGetStageParams(eq(mEntry))).thenReturn(null);
+
+        mViewBinder.unbindHeadsUpView(mEntry);
+        verify(mLogger).entryBindStageParamsNullOnUnbind(eq(mEntry));
+        verifyNoMoreInteractions(mLogger);
+        clearInvocations(mLogger);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index ad3bd71..7c99568 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -21,6 +21,10 @@
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -31,6 +35,7 @@
 
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.Log;
 
 import androidx.test.filters.SmallTest;
 
@@ -100,6 +105,67 @@
         verify(mBinder).unbindContent(eq(mEntry), any(), eq(flags));
     }
 
+    class CountingWtfHandler implements Log.TerribleFailureHandler {
+        private Log.TerribleFailureHandler mOldHandler = null;
+        private int mWtfCount = 0;
+
+        public void register() {
+            mOldHandler = Log.setWtfHandler(this);
+        }
+
+        public void unregister() {
+            Log.setWtfHandler(mOldHandler);
+            mOldHandler = null;
+        }
+
+        @Override
+        public void onTerribleFailure(String tag, Log.TerribleFailure what, boolean system) {
+            mWtfCount++;
+        }
+
+        public int getWtfCount() {
+            return mWtfCount;
+        }
+    }
+
+    @Test
+    public void testGetStageParamsAfterCleanUp() {
+        // GIVEN an entry whose params have already been deleted.
+        RowContentBindParams originalParams = mRowContentBindStage.getStageParams(mEntry);
+        mRowContentBindStage.deleteStageParams(mEntry);
+
+        // WHEN a caller calls getStageParams.
+        CountingWtfHandler countingWtfHandler = new CountingWtfHandler();
+        countingWtfHandler.register();
+
+        RowContentBindParams blankParams = mRowContentBindStage.getStageParams(mEntry);
+
+        countingWtfHandler.unregister();
+
+        // THEN getStageParams logs a WTF and returns blank params created to avoid a crash.
+        assertEquals(1, countingWtfHandler.getWtfCount());
+        assertNotNull(blankParams);
+        assertNotSame(originalParams, blankParams);
+    }
+
+    @Test
+    public void testTryGetStageParamsAfterCleanUp() {
+        // GIVEN an entry whose params have already been deleted.
+        mRowContentBindStage.deleteStageParams(mEntry);
+
+        // WHEN a caller calls getStageParams.
+        CountingWtfHandler countingWtfHandler = new CountingWtfHandler();
+        countingWtfHandler.register();
+
+        RowContentBindParams nullParams = mRowContentBindStage.tryGetStageParams(mEntry);
+
+        countingWtfHandler.unregister();
+
+        // THEN getStageParams does NOT log a WTF and returns null to indicate missing params.
+        assertEquals(0, countingWtfHandler.getWtfCount());
+        assertNull(nullParams);
+    }
+
     @Test
     public void testRebindAllContentViews() {
         // GIVEN a view with content bound.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
index 76ecc1c..169f4fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
@@ -57,14 +57,18 @@
 import com.android.systemui.shade.NotificationShadeWindowView
 import com.android.systemui.telephony.TelephonyListenerManager
 import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.legacyhelper.data.LegacyUserDataHelper
+import com.android.systemui.user.shared.model.UserActionModel
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
 import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.settings.GlobalSettings
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNotNull
@@ -123,7 +127,7 @@
     private val ownerId = UserHandle.USER_SYSTEM
     private val ownerInfo = UserInfo(ownerId, "Owner", null,
             UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or
-                    UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM,
+                    UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM or UserInfo.FLAG_ADMIN,
             UserManager.USER_TYPE_FULL_SYSTEM)
     private val guestId = 1234
     private val guestInfo = UserInfo(guestId, "Guest", null,
@@ -597,6 +601,76 @@
     }
 
     @Test
+    fun testCanManageUser_userSwitcherEnabled_addUserWhenLocked() {
+        `when`(
+            globalSettings.getIntForUser(
+                eq(Settings.Global.USER_SWITCHER_ENABLED),
+                anyInt(),
+                eq(UserHandle.USER_SYSTEM)
+            )
+        ).thenReturn(1)
+
+        `when`(
+            globalSettings.getIntForUser(
+                eq(Settings.Global.ADD_USERS_WHEN_LOCKED),
+                anyInt(),
+                eq(UserHandle.USER_SYSTEM)
+            )
+        ).thenReturn(1)
+        setupController()
+        assertTrue(userSwitcherController.canManageUsers())
+    }
+
+    @Test
+    fun testCanManageUser_userSwitcherDisabled_addUserWhenLocked() {
+        `when`(
+            globalSettings.getIntForUser(
+                eq(Settings.Global.USER_SWITCHER_ENABLED),
+                anyInt(),
+                eq(UserHandle.USER_SYSTEM)
+            )
+        ).thenReturn(0)
+
+        `when`(
+            globalSettings.getIntForUser(
+                eq(Settings.Global.ADD_USERS_WHEN_LOCKED),
+                anyInt(),
+                eq(UserHandle.USER_SYSTEM)
+            )
+        ).thenReturn(1)
+        setupController()
+        assertFalse(userSwitcherController.canManageUsers())
+    }
+
+    @Test
+    fun testCanManageUser_userSwitcherEnabled_isAdmin() {
+        `when`(
+            globalSettings.getIntForUser(
+                eq(Settings.Global.USER_SWITCHER_ENABLED),
+                anyInt(),
+                eq(UserHandle.USER_SYSTEM)
+            )
+        ).thenReturn(1)
+
+        setupController()
+        assertTrue(userSwitcherController.canManageUsers())
+    }
+
+    @Test
+    fun testCanManageUser_userSwitcherDisabled_isAdmin() {
+        `when`(
+            globalSettings.getIntForUser(
+                eq(Settings.Global.USER_SWITCHER_ENABLED),
+                anyInt(),
+                eq(UserHandle.USER_SYSTEM)
+            )
+        ).thenReturn(0)
+
+        setupController()
+        assertFalse(userSwitcherController.canManageUsers())
+    }
+
+    @Test
     fun addUserSwitchCallback() {
         val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>()
         verify(broadcastDispatcher).registerReceiver(
@@ -632,4 +706,22 @@
         bgExecutor.runAllReady()
         verify(userManager).createGuest(context)
     }
+
+    @Test
+    fun onUserItemClicked_manageUsers() {
+        val manageUserRecord = LegacyUserDataHelper.createRecord(
+            mContext,
+            ownerId,
+            UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+            isRestricted = false,
+            isSwitchToEnabled = true
+        )
+
+        userSwitcherController.onUserListItemClicked(manageUserRecord, null)
+        val intentCaptor = kotlinArgumentCaptor<Intent>()
+        verify(activityStarter).startActivity(intentCaptor.capture(),
+            eq(true)
+        )
+        Truth.assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
deleted file mode 100644
index 3968bb7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2022 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.user
-
-import android.app.Application
-import android.os.UserManager
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
-import android.view.LayoutInflater
-import android.view.View
-import android.view.Window
-import android.window.OnBackInvokedCallback
-import android.window.OnBackInvokedDispatcher
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.UserSwitcherController
-import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper(setAsMainLooper = true)
-class UserSwitcherActivityTest : SysuiTestCase() {
-    @Mock
-    private lateinit var activity: UserSwitcherActivity
-    @Mock
-    private lateinit var userSwitcherController: UserSwitcherController
-    @Mock
-    private lateinit var broadcastDispatcher: BroadcastDispatcher
-    @Mock
-    private lateinit var layoutInflater: LayoutInflater
-    @Mock
-    private lateinit var falsingCollector: FalsingCollector
-    @Mock
-    private lateinit var falsingManager: FalsingManager
-    @Mock
-    private lateinit var userManager: UserManager
-    @Mock
-    private lateinit var userTracker: UserTracker
-    @Mock
-    private lateinit var flags: FeatureFlags
-    @Mock
-    private lateinit var viewModelFactoryLazy: dagger.Lazy<UserSwitcherViewModel.Factory>
-    @Mock
-    private lateinit var onBackDispatcher: OnBackInvokedDispatcher
-    @Mock
-    private lateinit var decorView: View
-    @Mock
-    private lateinit var window: Window
-    @Mock
-    private lateinit var userSwitcherRootView: UserSwitcherRootView
-    @Captor
-    private lateinit var onBackInvokedCallback: ArgumentCaptor<OnBackInvokedCallback>
-    var isFinished = false
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        activity = spy(object : UserSwitcherActivity(
-            userSwitcherController,
-            broadcastDispatcher,
-            falsingCollector,
-            falsingManager,
-            userManager,
-            userTracker,
-            flags,
-            viewModelFactoryLazy,
-        ) {
-            override fun getOnBackInvokedDispatcher() = onBackDispatcher
-            override fun getMainExecutor(): Executor = FakeExecutor(FakeSystemClock())
-            override fun finish() {
-                isFinished = true
-            }
-        })
-        `when`(activity.window).thenReturn(window)
-        `when`(window.decorView).thenReturn(decorView)
-        `when`(activity.findViewById<UserSwitcherRootView>(R.id.user_switcher_root))
-                .thenReturn(userSwitcherRootView)
-        `when`(activity.findViewById<View>(R.id.cancel)).thenReturn(mock(View::class.java))
-        `when`(activity.findViewById<View>(R.id.add)).thenReturn(mock(View::class.java))
-        `when`(activity.application).thenReturn(mock(Application::class.java))
-        doNothing().`when`(activity).setContentView(anyInt())
-    }
-
-    @Test
-    fun testMaxColumns() {
-        assertThat(activity.getMaxColumns(3)).isEqualTo(4)
-        assertThat(activity.getMaxColumns(4)).isEqualTo(4)
-        assertThat(activity.getMaxColumns(5)).isEqualTo(3)
-        assertThat(activity.getMaxColumns(6)).isEqualTo(3)
-        assertThat(activity.getMaxColumns(7)).isEqualTo(4)
-        assertThat(activity.getMaxColumns(9)).isEqualTo(5)
-    }
-
-    @Test
-    fun onCreate_callbackRegistration() {
-        activity.createActivity()
-        verify(onBackDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any())
-
-        activity.destroyActivity()
-        verify(onBackDispatcher).unregisterOnBackInvokedCallback(any())
-    }
-
-    @Test
-    fun onBackInvokedCallback_finishesActivity() {
-        activity.createActivity()
-        verify(onBackDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), onBackInvokedCallback.capture())
-
-        onBackInvokedCallback.value.onBackInvoked()
-        assertThat(isFinished).isTrue()
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
index 37c378c..1540f85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
@@ -202,6 +202,7 @@
     fun `actions - device unlocked`() =
         runBlocking(IMMEDIATE) {
             val userInfos = createUserInfos(count = 2, includeGuest = false)
+
             userRepository.setUserInfos(userInfos)
             userRepository.setSelectedUserInfo(userInfos[0])
             userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -215,6 +216,7 @@
                         UserActionModel.ENTER_GUEST_MODE,
                         UserActionModel.ADD_USER,
                         UserActionModel.ADD_SUPERVISED_USER,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
                     )
                 )
 
@@ -276,6 +278,7 @@
                         UserActionModel.ENTER_GUEST_MODE,
                         UserActionModel.ADD_USER,
                         UserActionModel.ADD_SUPERVISED_USER,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
                     )
                 )
 
@@ -283,7 +286,7 @@
         }
 
     @Test
-    fun `actions - device locked - only guest action is shown`() =
+    fun `actions - device locked - only guest action and manage user is shown`() =
         runBlocking(IMMEDIATE) {
             val userInfos = createUserInfos(count = 2, includeGuest = false)
             userRepository.setUserInfos(userInfos)
@@ -293,7 +296,13 @@
             var value: List<UserActionModel>? = null
             val job = underTest.actions.onEach { value = it }.launchIn(this)
 
-            assertThat(value).isEqualTo(listOf(UserActionModel.ENTER_GUEST_MODE))
+            assertThat(value)
+                .isEqualTo(
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT
+                    )
+                )
 
             job.cancel()
         }
@@ -330,7 +339,7 @@
             underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
 
             val intentCaptor = kotlinArgumentCaptor<Intent>()
-            verify(activityStarter).startActivity(intentCaptor.capture(), eq(false))
+            verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
             assertThat(intentCaptor.value.action)
                 .isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER)
             assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE)
@@ -342,7 +351,7 @@
             underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
 
             val intentCaptor = kotlinArgumentCaptor<Intent>()
-            verify(activityStarter).startActivity(intentCaptor.capture(), eq(false))
+            verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
             assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
         }
 
@@ -561,6 +570,7 @@
                         UserActionModel.ENTER_GUEST_MODE,
                         UserActionModel.ADD_USER,
                         UserActionModel.ADD_SUPERVISED_USER,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
                     ),
             )
         }
@@ -705,7 +715,7 @@
             name,
             /* iconPath= */ "",
             /* flags= */ if (isPrimary) {
-                UserInfo.FLAG_PRIMARY
+                UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN
             } else {
                 0
             },
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index aec5f5e..4cf63b3 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3732,21 +3732,34 @@
             Slog.w(TAG, "agentDisconnected: the backup agent for " + packageName
                     + " died: cancel current operations");
 
-            // handleCancel() causes the PerformFullTransportBackupTask to go on to
-            // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
-            // that the package being backed up doesn't get stuck in restricted mode until the
-            // backup time-out elapses.
-            for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
-                if (MORE_DEBUG) {
-                    Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:"
-                            + Integer.toHexString(token));
+            // Offload operation cancellation off the main thread as the cancellation callbacks
+            // might call out to BackupTransport. Other operations started on the same package
+            // before the cancellation callback has executed will also be cancelled by the callback.
+            Runnable cancellationRunnable = () -> {
+                // handleCancel() causes the PerformFullTransportBackupTask to go on to
+                // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
+                // that the package being backed up doesn't get stuck in restricted mode until the
+                // backup time-out elapses.
+                for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
+                    if (MORE_DEBUG) {
+                        Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:"
+                                + Integer.toHexString(token));
+                    }
+                    handleCancel(token, true /* cancelAll */);
                 }
-                handleCancel(token, true /* cancelAll */);
-            }
+            };
+            getThreadForAsyncOperation(/* operationName */ "agent-disconnected",
+                    cancellationRunnable).start();
+
             mAgentConnectLock.notifyAll();
         }
     }
 
+    @VisibleForTesting
+    Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
+        return new Thread(operation, operationName);
+    }
+
     /**
      * An application being installed will need a restore pass, then the {@link PackageManager} will
      * need to be told when the restore is finished.
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index fb8c5b1..41b62e6 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -363,7 +363,9 @@
         @Override
         public void handleMessage(@NonNull Message msg) {
             final int associationId = msg.what;
-            onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+            if (mSimulated.contains(associationId)) {
+                onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+            }
         }
     }
 }
diff --git a/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
similarity index 99%
rename from core/java/com/android/server/SystemConfig.java
rename to services/core/java/com/android/server/SystemConfig.java
index 2c9ef4f..b7f8d38 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -72,6 +72,8 @@
  * Loads global system configuration info.
  * Note: Initializing this class hits the disk and is slow.  This class should generally only be
  * accessed by the system_server process.
+ *
+ * @hide
  */
 public class SystemConfig {
     static final String TAG = "SystemConfig";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 593e21a5..1a4da7d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3937,7 +3937,8 @@
                     // Clear its scheduled jobs
                     JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
                     // Clearing data is a user-initiated action.
-                    js.cancelJobsForUid(appInfo.uid, JobParameters.STOP_REASON_USER,
+                    js.cancelJobsForUid(appInfo.uid, /* includeProxiedJobs */ true,
+                            JobParameters.STOP_REASON_USER,
                             JobParameters.INTERNAL_STOP_REASON_DATA_CLEARED, "clear data");
 
                     // Clear its pending alarms
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 23c020e..3c1bf0b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -1138,10 +1138,7 @@
         mHandler.removeCallbacksAndMessages(null);
 
         // Release any outstanding wakelocks we're still holding because of pending messages.
-        mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
-        mWakelockController.releaseStateChangedSuspendBlocker();
-        mWakelockController.releaseProxPositiveSuspendBlocker();
-        mWakelockController.releaseProxNegativeSuspendBlocker();
+        mWakelockController.releaseAll();
 
         final float brightness = mPowerState != null
                 ? mPowerState.getScreenBrightness()
@@ -1729,7 +1726,7 @@
 
         // Grab a wake lock if we have unfinished business.
         if (!finished) {
-            mWakelockController.acquireUnfinishedBusinessSuspendBlocker();
+            mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
         }
 
         // Notify the power manager when ready.
@@ -1749,7 +1746,7 @@
 
         // Release the wake lock when we have no unfinished business.
         if (finished) {
-            mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
+            mWakelockController.releaseWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
         }
 
         // Record if dozing for future comparison.
@@ -2248,7 +2245,8 @@
                 mSensorManager.unregisterListener(mProximitySensorListener);
                 // release wake lock(must be last)
                 boolean proxDebounceSuspendBlockerReleased =
-                        mWakelockController.releaseProxDebounceSuspendBlocker();
+                        mWakelockController.releaseWakelock(
+                                WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
                 if (proxDebounceSuspendBlockerReleased) {
                     mPendingProximityDebounceTime = -1;
                 }
@@ -2272,11 +2270,13 @@
             if (positive) {
                 mPendingProximity = PROXIMITY_POSITIVE;
                 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
-                mWakelockController.acquireProxDebounceSuspendBlocker(); // acquire wake lock
+                mWakelockController.acquireWakelock(
+                        WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock
             } else {
                 mPendingProximity = PROXIMITY_NEGATIVE;
                 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
-                mWakelockController.acquireProxDebounceSuspendBlocker(); // acquire wake lock
+                mWakelockController.acquireWakelock(
+                        WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock
             }
 
             // Debounce the new sensor reading.
@@ -2300,7 +2300,8 @@
                 updatePowerState();
                 // (must be last)
                 boolean proxDebounceSuspendBlockerReleased =
-                        mWakelockController.releaseProxDebounceSuspendBlocker();
+                        mWakelockController.releaseWakelock(
+                                WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
                 if (proxDebounceSuspendBlockerReleased) {
                     mPendingProximityDebounceTime = -1;
                 }
@@ -2315,7 +2316,8 @@
     }
 
     private void sendOnStateChangedWithWakelock() {
-        boolean wakeLockAcquired = mWakelockController.acquireStateChangedSuspendBlocker();
+        boolean wakeLockAcquired = mWakelockController.acquireWakelock(
+                WakelockController.WAKE_LOCK_STATE_CHANGED);
         if (wakeLockAcquired) {
             mHandler.post(mWakelockController.getOnStateChangedRunnable());
         }
@@ -2479,13 +2481,13 @@
     }
 
     private void sendOnProximityPositiveWithWakelock() {
-        mWakelockController.acquireProxPositiveSuspendBlocker();
+        mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE);
         mHandler.post(mWakelockController.getOnProximityPositiveRunnable());
     }
 
 
     private void sendOnProximityNegativeWithWakelock() {
-        mWakelockController.acquireProxNegativeSuspendBlocker();
+        mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE);
         mHandler.post(mWakelockController.getOnProximityNegativeRunnable());
     }
 
diff --git a/services/core/java/com/android/server/display/WakelockController.java b/services/core/java/com/android/server/display/WakelockController.java
index cbf559f..6511f4f 100644
--- a/services/core/java/com/android/server/display/WakelockController.java
+++ b/services/core/java/com/android/server/display/WakelockController.java
@@ -16,12 +16,15 @@
 
 package com.android.server.display;
 
+import android.annotation.IntDef;
 import android.hardware.display.DisplayManagerInternal;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * A utility class to acquire/release suspend blockers and manage appropriate states around it.
@@ -29,8 +32,26 @@
  * display states as needed.
  */
 public final class WakelockController {
+    public static final int WAKE_LOCK_PROXIMITY_POSITIVE = 1;
+    public static final int WAKE_LOCK_PROXIMITY_NEGATIVE = 2;
+    public static final int WAKE_LOCK_PROXIMITY_DEBOUNCE = 3;
+    public static final int WAKE_LOCK_STATE_CHANGED = 4;
+    public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 5;
+
+    private static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS;
     private static final boolean DEBUG = false;
 
+    @IntDef(flag = true, prefix = "WAKE_LOCK_", value = {
+            WAKE_LOCK_PROXIMITY_POSITIVE,
+            WAKE_LOCK_PROXIMITY_NEGATIVE,
+            WAKE_LOCK_PROXIMITY_DEBOUNCE,
+            WAKE_LOCK_STATE_CHANGED,
+            WAKE_LOCK_UNFINISHED_BUSINESS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WAKE_LOCK_TYPE {
+    }
+
     // Asynchronous callbacks into the power manager service.
     // Only invoked from the handler thread while no locks are held.
     private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks;
@@ -58,17 +79,17 @@
     // (i.e. DisplayPowerController2).
     private boolean mOnStateChangedPending;
 
-    // Count of positive proximity messages currently held. Used to keep track of how many
-    // suspend blocker acquisitions are pending when shutting down the DisplayPowerController2.
-    // Should only be accessed on the Handler thread of the class managing the Display states
-    // (i.e. DisplayPowerController2).
-    private int mOnProximityPositiveMessages;
+    // When true, it implies that a positive proximity wakelock is currently held. Used to keep
+    // track if suspend blocker acquisitions is pending when shutting down the
+    // DisplayPowerController2. Should only be accessed on the Handler thread of the class
+    // managing the Display states (i.e. DisplayPowerController2).
+    private boolean mIsProximityPositiveAcquired;
 
-    // Count of negative proximity messages currently held. Used to keep track of how many
-    // suspend blocker acquisitions are pending when shutting down the DisplayPowerController2.
-    // Should only be accessed on the Handler thread of the class managing the Display states
-    // (i.e. DisplayPowerController2).
-    private int mOnProximityNegativeMessages;
+    // When true, it implies that a negative proximity wakelock is currently held. Used to keep
+    // track if suspend blocker acquisitions is pending when shutting down the
+    // DisplayPowerController2. Should only be accessed on the Handler thread of the class
+    // managing the Display states (i.e. DisplayPowerController2).
+    private boolean mIsProximityNegativeAcquired;
 
     /**
      * The constructor of WakelockController. Manages the initialization of all the local entities
@@ -87,9 +108,86 @@
     }
 
     /**
+     * A utility to acquire a wakelock
+     *
+     * @param wakelock The type of Wakelock to be acquired
+     * @return True of the wakelock is successfully acquired. False if it is already acquired
+     */
+    public boolean acquireWakelock(@WAKE_LOCK_TYPE int wakelock) {
+        return acquireWakelockInternal(wakelock);
+    }
+
+    /**
+     * A utility to release a wakelock
+     *
+     * @param wakelock The type of Wakelock to be released
+     * @return True of an acquired wakelock is successfully released. False if it is already
+     * acquired
+     */
+    public boolean releaseWakelock(@WAKE_LOCK_TYPE int wakelock) {
+        return releaseWakelockInternal(wakelock);
+    }
+
+    /**
+     * A utility to release all the wakelock acquired by the system
+     */
+    public void releaseAll() {
+        for (int i = WAKE_LOCK_PROXIMITY_POSITIVE; i < WAKE_LOCK_MAX; i++) {
+            releaseWakelockInternal(i);
+        }
+    }
+
+    private boolean acquireWakelockInternal(@WAKE_LOCK_TYPE int wakelock) {
+        switch (wakelock) {
+            case WAKE_LOCK_PROXIMITY_POSITIVE:
+                return acquireProxPositiveSuspendBlocker();
+            case WAKE_LOCK_PROXIMITY_NEGATIVE:
+                return acquireProxNegativeSuspendBlocker();
+            case WAKE_LOCK_PROXIMITY_DEBOUNCE:
+                return acquireProxDebounceSuspendBlocker();
+            case WAKE_LOCK_STATE_CHANGED:
+                return acquireStateChangedSuspendBlocker();
+            case WAKE_LOCK_UNFINISHED_BUSINESS:
+                return acquireUnfinishedBusinessSuspendBlocker();
+            default:
+                throw new RuntimeException("Invalid wakelock attempted to be acquired");
+        }
+    }
+
+    private boolean releaseWakelockInternal(@WAKE_LOCK_TYPE int wakelock) {
+        switch (wakelock) {
+            case WAKE_LOCK_PROXIMITY_POSITIVE:
+                return releaseProxPositiveSuspendBlocker();
+            case WAKE_LOCK_PROXIMITY_NEGATIVE:
+                return releaseProxNegativeSuspendBlocker();
+            case WAKE_LOCK_PROXIMITY_DEBOUNCE:
+                return releaseProxDebounceSuspendBlocker();
+            case WAKE_LOCK_STATE_CHANGED:
+                return releaseStateChangedSuspendBlocker();
+            case WAKE_LOCK_UNFINISHED_BUSINESS:
+                return releaseUnfinishedBusinessSuspendBlocker();
+            default:
+                throw new RuntimeException("Invalid wakelock attempted to be released");
+        }
+    }
+
+    /**
+     * Acquires the proximity positive wakelock and notifies the PowerManagerService about the
+     * changes.
+     */
+    private boolean acquireProxPositiveSuspendBlocker() {
+        if (!mIsProximityPositiveAcquired) {
+            mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive);
+            mIsProximityPositiveAcquired = true;
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Acquires the state change wakelock and notifies the PowerManagerService about the changes.
      */
-    public boolean acquireStateChangedSuspendBlocker() {
+    private boolean acquireStateChangedSuspendBlocker() {
         // Grab a wake lock if we have change of the display state
         if (!mOnStateChangedPending) {
             if (DEBUG) {
@@ -105,18 +203,20 @@
     /**
      * Releases the state change wakelock and notifies the PowerManagerService about the changes.
      */
-    public void releaseStateChangedSuspendBlocker() {
+    private boolean releaseStateChangedSuspendBlocker() {
         if (mOnStateChangedPending) {
             mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged);
             mOnStateChangedPending = false;
+            return true;
         }
+        return false;
     }
 
     /**
      * Acquires the unfinished business wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public void acquireUnfinishedBusinessSuspendBlocker() {
+    private boolean acquireUnfinishedBusinessSuspendBlocker() {
         // Grab a wake lock if we have unfinished business.
         if (!mUnfinishedBusiness) {
             if (DEBUG) {
@@ -124,79 +224,84 @@
             }
             mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness);
             mUnfinishedBusiness = true;
+            return true;
         }
+        return false;
     }
 
     /**
      * Releases the unfinished business wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public void releaseUnfinishedBusinessSuspendBlocker() {
+    private boolean releaseUnfinishedBusinessSuspendBlocker() {
         if (mUnfinishedBusiness) {
             if (DEBUG) {
                 Slog.d(mTag, "Finished business...");
             }
             mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness);
             mUnfinishedBusiness = false;
+            return true;
         }
-    }
-
-    /**
-     * Acquires the proximity positive wakelock and notifies the PowerManagerService about the
-     * changes.
-     */
-    public void acquireProxPositiveSuspendBlocker() {
-        mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive);
-        mOnProximityPositiveMessages++;
+        return false;
     }
 
     /**
      * Releases the proximity positive wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public void releaseProxPositiveSuspendBlocker() {
-        for (int i = 0; i < mOnProximityPositiveMessages; i++) {
+    private boolean releaseProxPositiveSuspendBlocker() {
+        if (mIsProximityPositiveAcquired) {
             mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive);
+            mIsProximityPositiveAcquired = false;
+            return true;
         }
-        mOnProximityPositiveMessages = 0;
+        return false;
     }
 
     /**
      * Acquires the proximity negative wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public void acquireProxNegativeSuspendBlocker() {
-        mOnProximityNegativeMessages++;
-        mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative);
+    private boolean acquireProxNegativeSuspendBlocker() {
+        if (!mIsProximityNegativeAcquired) {
+            mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative);
+            mIsProximityNegativeAcquired = true;
+            return true;
+        }
+        return false;
     }
 
     /**
      * Releases the proximity negative wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public void releaseProxNegativeSuspendBlocker() {
-        for (int i = 0; i < mOnProximityNegativeMessages; i++) {
+    private boolean releaseProxNegativeSuspendBlocker() {
+        if (mIsProximityNegativeAcquired) {
             mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative);
+            mIsProximityNegativeAcquired = false;
+            return true;
         }
-        mOnProximityNegativeMessages = 0;
+        return false;
     }
 
     /**
      * Acquires the proximity debounce wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public void acquireProxDebounceSuspendBlocker() {
+    private boolean acquireProxDebounceSuspendBlocker() {
         if (!mHasProximityDebounced) {
             mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxDebounce);
+            mHasProximityDebounced = true;
+            return true;
         }
-        mHasProximityDebounced = true;
+        return false;
     }
 
     /**
      * Releases the proximity debounce wakelock and notifies the PowerManagerService about the
      * changes.
      */
-    public boolean releaseProxDebounceSuspendBlocker() {
+    private boolean releaseProxDebounceSuspendBlocker() {
         if (mHasProximityDebounced) {
             mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxDebounce);
             mHasProximityDebounced = false;
@@ -210,9 +315,11 @@
      */
     public Runnable getOnProximityPositiveRunnable() {
         return () -> {
-            mOnProximityPositiveMessages--;
-            mDisplayPowerCallbacks.onProximityPositive();
-            mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive);
+            if (mIsProximityPositiveAcquired) {
+                mIsProximityPositiveAcquired = false;
+                mDisplayPowerCallbacks.onProximityPositive();
+                mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive);
+            }
         };
     }
 
@@ -221,9 +328,11 @@
      */
     public Runnable getOnStateChangedRunnable() {
         return () -> {
-            mOnStateChangedPending = false;
-            mDisplayPowerCallbacks.onStateChanged();
-            mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged);
+            if (mOnStateChangedPending) {
+                mOnStateChangedPending = false;
+                mDisplayPowerCallbacks.onStateChanged();
+                mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged);
+            }
         };
     }
 
@@ -232,9 +341,11 @@
      */
     public Runnable getOnProximityNegativeRunnable() {
         return () -> {
-            mOnProximityNegativeMessages--;
-            mDisplayPowerCallbacks.onProximityNegative();
-            mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative);
+            if (mIsProximityNegativeAcquired) {
+                mIsProximityNegativeAcquired = false;
+                mDisplayPowerCallbacks.onProximityNegative();
+                mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative);
+            }
         };
     }
 
@@ -246,8 +357,8 @@
         pw.println("  mDisplayId=" + mDisplayId);
         pw.println("  mUnfinishedBusiness=" + hasUnfinishedBusiness());
         pw.println("  mOnStateChangePending=" + isOnStateChangedPending());
-        pw.println("  mOnProximityPositiveMessages=" + getOnProximityPositiveMessages());
-        pw.println("  mOnProximityNegativeMessages=" + getOnProximityNegativeMessages());
+        pw.println("  mOnProximityPositiveMessages=" + isProximityPositiveAcquired());
+        pw.println("  mOnProximityNegativeMessages=" + isProximityNegativeAcquired());
     }
 
     @VisibleForTesting
@@ -286,13 +397,13 @@
     }
 
     @VisibleForTesting
-    int getOnProximityPositiveMessages() {
-        return mOnProximityPositiveMessages;
+    boolean isProximityPositiveAcquired() {
+        return mIsProximityPositiveAcquired;
     }
 
     @VisibleForTesting
-    int getOnProximityNegativeMessages() {
-        return mOnProximityNegativeMessages;
+    boolean isProximityNegativeAcquired() {
+        return mIsProximityNegativeAcquired;
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index be3a4da..6b31555 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -54,6 +54,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.pkg.AndroidPackage;
@@ -1005,11 +1006,14 @@
     /** @see ApplicationInfo#privateFlagsExt */
     public static int appInfoPrivateFlagsExt(AndroidPackage pkg,
                                              @Nullable PackageStateInternal pkgSetting) {
+        var isAllowlistedForHiddenApis = SystemConfig.getInstance().getHiddenApiWhitelistedApps()
+                .contains(pkg.getPackageName());
         // @formatter:off
         int pkgWithoutStateFlags = flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
                 | flag(pkg.hasRequestForegroundServiceExemption(), ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
                 | flag(pkg.areAttributionsUserVisible(), ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
-                | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK);
+                | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)
+                | flag(isAllowlistedForHiddenApis, ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS);
         return appInfoPrivateFlagsExt(pkgWithoutStateFlags, pkgSetting);
         // @formatter:on
     }
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index cb52e5f..6e82907 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -101,6 +101,13 @@
             }
             return enabledComponent;
         }
+
+        @Override
+        public List<ComponentName> getDefaultVrComponents() {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.QUERY_ALL_PACKAGES,
+                    "Caller must hold " + Manifest.permission.QUERY_ALL_PACKAGES);
+            return new ArrayList<>(SystemConfig.getInstance().getDefaultVrComponents());
+        }
     };
 
     public SystemConfigService(Context context) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 2df6823a..20af02e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -177,15 +177,19 @@
         advanceTime(1);
 
         // two times, one for unfinished business and one for proximity
-        verify(mWakelockController).acquireUnfinishedBusinessSuspendBlocker();
-        verify(mWakelockController).acquireProxDebounceSuspendBlocker();
+        verify(mWakelockController).acquireWakelock(
+                WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
+        verify(mWakelockController).acquireWakelock(
+                WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
 
 
         dpc.stop();
         advanceTime(1);
         // two times, one for unfinished business and one for proximity
-        verify(mWakelockController).acquireUnfinishedBusinessSuspendBlocker();
-        verify(mWakelockController).acquireProxDebounceSuspendBlocker();
+        verify(mWakelockController).acquireWakelock(
+                WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
+        verify(mWakelockController).acquireWakelock(
+                WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
     }
 
     /**
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
index 288408c..07a81ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.hardware.display.DisplayManagerInternal;
 
@@ -33,6 +34,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.Callable;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public final class WakelockControllerTest {
@@ -64,25 +67,18 @@
     }
 
     @Test
-    public void acquireStateChangedSuspendBlockerAcquiresIfNotAcquired() {
-        // Acquire the suspend blocker
-        assertTrue(mWakelockController.acquireStateChangedSuspendBlocker());
-        assertTrue(mWakelockController.isOnStateChangedPending());
-
-        // Try to reacquire
-        assertFalse(mWakelockController.acquireStateChangedSuspendBlocker());
-        assertTrue(mWakelockController.isOnStateChangedPending());
+    public void acquireStateChangedSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+        // Acquire
+        verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_STATE_CHANGED,
+                () -> mWakelockController.isOnStateChangedPending());
 
         // Verify acquire happened only once
         verify(mDisplayPowerCallbacks, times(1))
                 .acquireSuspendBlocker(mWakelockController.getSuspendBlockerOnStateChangedId());
 
         // Release
-        mWakelockController.releaseStateChangedSuspendBlocker();
-        assertFalse(mWakelockController.isOnStateChangedPending());
-
-        // Try to release again
-        mWakelockController.releaseStateChangedSuspendBlocker();
+        verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_STATE_CHANGED,
+                () -> mWakelockController.isOnStateChangedPending());
 
         // Verify release happened only once
         verify(mDisplayPowerCallbacks, times(1))
@@ -90,25 +86,18 @@
     }
 
     @Test
-    public void acquireUnfinishedBusinessSuspendBlockerAcquiresIfNotAcquired() {
-        // Acquire the suspend blocker
-        mWakelockController.acquireUnfinishedBusinessSuspendBlocker();
-        assertTrue(mWakelockController.hasUnfinishedBusiness());
-
-        // Try to reacquire
-        mWakelockController.acquireUnfinishedBusinessSuspendBlocker();
-        assertTrue(mWakelockController.hasUnfinishedBusiness());
+    public void acquireUnfinishedBusinessSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+        // Acquire
+        verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS,
+                () -> mWakelockController.hasUnfinishedBusiness());
 
         // Verify acquire happened only once
         verify(mDisplayPowerCallbacks, times(1))
                 .acquireSuspendBlocker(mWakelockController.getSuspendBlockerUnfinishedBusinessId());
 
-        // Release the suspend blocker
-        mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
-        assertFalse(mWakelockController.hasUnfinishedBusiness());
-
-        // Try to release again
-        mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
+        // Release
+        verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS,
+                () -> mWakelockController.hasUnfinishedBusiness());
 
         // Verify release happened only once
         verify(mDisplayPowerCallbacks, times(1))
@@ -116,70 +105,56 @@
     }
 
     @Test
-    public void acquireProxPositiveSuspendBlockerAcquiresIfNotAcquired() {
-        // Acquire the suspend blocker
-        mWakelockController.acquireProxPositiveSuspendBlocker();
-        assertEquals(mWakelockController.getOnProximityPositiveMessages(), 1);
-
-        // Try to reacquire
-        mWakelockController.acquireProxPositiveSuspendBlocker();
-        assertEquals(mWakelockController.getOnProximityPositiveMessages(), 2);
+    public void acquireProxPositiveSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+        // Acquire
+        verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE,
+                () -> mWakelockController.isProximityPositiveAcquired());
 
         // Verify acquire happened only once
-        verify(mDisplayPowerCallbacks, times(2))
+        verify(mDisplayPowerCallbacks, times(1))
                 .acquireSuspendBlocker(mWakelockController.getSuspendBlockerProxPositiveId());
 
-        // Release the suspend blocker
-        mWakelockController.releaseProxPositiveSuspendBlocker();
-        assertEquals(mWakelockController.getOnProximityPositiveMessages(), 0);
+        // Release
+        verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE,
+                () -> mWakelockController.isProximityPositiveAcquired());
 
-        // Verify all suspend blockers were released
-        verify(mDisplayPowerCallbacks, times(2))
+        // Verify release happened only once
+        verify(mDisplayPowerCallbacks, times(1))
                 .releaseSuspendBlocker(mWakelockController.getSuspendBlockerProxPositiveId());
     }
 
     @Test
-    public void acquireProxNegativeSuspendBlockerAcquiresIfNotAcquired() {
-        // Acquire the suspend blocker
-        mWakelockController.acquireProxNegativeSuspendBlocker();
-        assertEquals(mWakelockController.getOnProximityNegativeMessages(), 1);
-
-        // Try to reacquire
-        mWakelockController.acquireProxNegativeSuspendBlocker();
-        assertEquals(mWakelockController.getOnProximityNegativeMessages(), 2);
+    public void acquireProxNegativeSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+        // Acquire
+        verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE,
+                () -> mWakelockController.isProximityNegativeAcquired());
 
         // Verify acquire happened only once
-        verify(mDisplayPowerCallbacks, times(2))
+        verify(mDisplayPowerCallbacks, times(1))
                 .acquireSuspendBlocker(mWakelockController.getSuspendBlockerProxNegativeId());
 
-        // Release the suspend blocker
-        mWakelockController.releaseProxNegativeSuspendBlocker();
-        assertEquals(mWakelockController.getOnProximityNegativeMessages(), 0);
+        // Release
+        verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE,
+                () -> mWakelockController.isProximityNegativeAcquired());
 
-        // Verify all suspend blockers were released
-        verify(mDisplayPowerCallbacks, times(2))
+        // Verify release happened only once
+        verify(mDisplayPowerCallbacks, times(1))
                 .releaseSuspendBlocker(mWakelockController.getSuspendBlockerProxNegativeId());
     }
 
     @Test
-    public void acquireProxDebounceSuspendBlockerAcquiresIfNotAcquired() {
+    public void acquireProxDebounceSuspendBlockerAcquiresIfNotAcquired() throws Exception {
         // Acquire the suspend blocker
-        mWakelockController.acquireProxDebounceSuspendBlocker();
-
-        // Try to reacquire
-        mWakelockController.acquireProxDebounceSuspendBlocker();
-        assertTrue(mWakelockController.hasProximitySensorDebounced());
+        verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE,
+                () -> mWakelockController.hasProximitySensorDebounced());
 
         // Verify acquire happened only once
         verify(mDisplayPowerCallbacks, times(1))
                 .acquireSuspendBlocker(mWakelockController.getSuspendBlockerProxDebounceId());
 
         // Release the suspend blocker
-        assertTrue(mWakelockController.releaseProxDebounceSuspendBlocker());
-
-        // Release again
-        assertFalse(mWakelockController.releaseProxDebounceSuspendBlocker());
-        assertFalse(mWakelockController.hasProximitySensorDebounced());
+        verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE,
+                () -> mWakelockController.hasProximitySensorDebounced());
 
         // Verify suspend blocker was released only once
         verify(mDisplayPowerCallbacks, times(1))
@@ -189,52 +164,126 @@
     @Test
     public void proximityPositiveRunnableWorksAsExpected() {
         // Acquire the suspend blocker twice
-        mWakelockController.acquireProxPositiveSuspendBlocker();
-        mWakelockController.acquireProxPositiveSuspendBlocker();
+        assertTrue(mWakelockController.acquireWakelock(
+                WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE));
 
         // Execute the runnable
         Runnable proximityPositiveRunnable = mWakelockController.getOnProximityPositiveRunnable();
         proximityPositiveRunnable.run();
 
         // Validate one suspend blocker was released
-        assertEquals(mWakelockController.getOnProximityPositiveMessages(), 1);
+        assertFalse(mWakelockController.isProximityPositiveAcquired());
         verify(mDisplayPowerCallbacks).onProximityPositive();
         verify(mDisplayPowerCallbacks).releaseSuspendBlocker(
                 mWakelockController.getSuspendBlockerProxPositiveId());
     }
 
     @Test
+    public void proximityPositiveRunnableDoesNothingIfNotAcquired() {
+        // Execute the runnable
+        Runnable proximityPositiveRunnable = mWakelockController.getOnProximityPositiveRunnable();
+        proximityPositiveRunnable.run();
+
+        // Validate one suspend blocker was released
+        assertFalse(mWakelockController.isProximityPositiveAcquired());
+        verifyZeroInteractions(mDisplayPowerCallbacks);
+    }
+
+    @Test
     public void proximityNegativeRunnableWorksAsExpected() {
         // Acquire the suspend blocker twice
-        mWakelockController.acquireProxNegativeSuspendBlocker();
-        mWakelockController.acquireProxNegativeSuspendBlocker();
+        assertTrue(mWakelockController.acquireWakelock(
+                WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE));
 
         // Execute the runnable
         Runnable proximityNegativeRunnable = mWakelockController.getOnProximityNegativeRunnable();
         proximityNegativeRunnable.run();
 
         // Validate one suspend blocker was released
-        assertEquals(mWakelockController.getOnProximityNegativeMessages(), 1);
+        assertFalse(mWakelockController.isProximityNegativeAcquired());
         verify(mDisplayPowerCallbacks).onProximityNegative();
         verify(mDisplayPowerCallbacks).releaseSuspendBlocker(
                 mWakelockController.getSuspendBlockerProxNegativeId());
     }
 
     @Test
+    public void proximityNegativeRunnableDoesNothingIfNotAcquired() {
+        // Execute the runnable
+        Runnable proximityNegativeRunnable = mWakelockController.getOnProximityNegativeRunnable();
+        proximityNegativeRunnable.run();
+
+        // Validate one suspend blocker was released
+        assertFalse(mWakelockController.isProximityNegativeAcquired());
+        verifyZeroInteractions(mDisplayPowerCallbacks);
+    }
+
+    @Test
     public void onStateChangeRunnableWorksAsExpected() {
         // Acquire the suspend blocker twice
-        mWakelockController.acquireStateChangedSuspendBlocker();
+        assertTrue(mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_STATE_CHANGED));
 
         // Execute the runnable
         Runnable stateChangeRunnable = mWakelockController.getOnStateChangedRunnable();
         stateChangeRunnable.run();
 
         // Validate one suspend blocker was released
-        assertEquals(mWakelockController.isOnStateChangedPending(), false);
+        assertFalse(mWakelockController.isOnStateChangedPending());
         verify(mDisplayPowerCallbacks).onStateChanged();
         verify(mDisplayPowerCallbacks).releaseSuspendBlocker(
                 mWakelockController.getSuspendBlockerOnStateChangedId());
     }
 
+    @Test
+    public void onStateChangeRunnableDoesNothingIfNotAcquired() {
+        // Execute the runnable
+        Runnable stateChangeRunnable = mWakelockController.getOnStateChangedRunnable();
+        stateChangeRunnable.run();
+
+        // Validate one suspend blocker was released
+        assertFalse(mWakelockController.isOnStateChangedPending());
+        verifyZeroInteractions(mDisplayPowerCallbacks);
+    }
+
+    private void verifyWakelockAcquisitionAndReaquisition(int wakelockId,
+            Callable<Boolean> isWakelockAcquiredCallable)
+            throws Exception {
+        verifyWakelockAcquisition(wakelockId, isWakelockAcquiredCallable);
+        verifyWakelockReacquisition(wakelockId, isWakelockAcquiredCallable);
+    }
+
+    private void verifyWakelockReleaseAndRerelease(int wakelockId,
+            Callable<Boolean> isWakelockAcquiredCallable)
+            throws Exception {
+        verifyWakelockRelease(wakelockId, isWakelockAcquiredCallable);
+        verifyWakelockRerelease(wakelockId, isWakelockAcquiredCallable);
+    }
+
+    private void verifyWakelockAcquisition(int wakelockId,
+            Callable<Boolean> isWakelockAcquiredCallable)
+            throws Exception {
+        assertTrue(mWakelockController.acquireWakelock(wakelockId));
+        assertTrue(isWakelockAcquiredCallable.call());
+    }
+
+    private void verifyWakelockReacquisition(int wakelockId,
+            Callable<Boolean> isWakelockAcquiredCallable)
+            throws Exception {
+        assertFalse(mWakelockController.acquireWakelock(wakelockId));
+        assertTrue(isWakelockAcquiredCallable.call());
+    }
+
+    private void verifyWakelockRelease(int wakelockId, Callable<Boolean> isWakelockAcquiredCallable)
+            throws Exception {
+        assertTrue(mWakelockController.releaseWakelock(wakelockId));
+        assertFalse(isWakelockAcquiredCallable.call());
+    }
+
+    private void verifyWakelockRerelease(int wakelockId,
+            Callable<Boolean> isWakelockAcquiredCallable)
+            throws Exception {
+        assertFalse(mWakelockController.releaseWakelock(wakelockId));
+        assertFalse(isWakelockAcquiredCallable.call());
+    }
+
 
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index cc57b9f..dc7bcd6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -38,6 +38,7 @@
 import android.os.incremental.IncrementalManager
 import android.provider.DeviceConfig
 import android.util.ArrayMap
+import android.util.ArraySet
 import android.util.DisplayMetrics
 import android.util.EventLog
 import android.view.Display
@@ -294,6 +295,8 @@
         wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
         whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP)
         whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
+        whenever(mocks.systemConfig.defaultVrComponents).thenReturn(ArraySet())
+        whenever(mocks.systemConfig.hiddenApiWhitelistedApps).thenReturn(ArraySet())
         wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true)
         wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
         wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index bccd8a0b..9ae8922 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -61,6 +62,7 @@
 public class UserBackupManagerServiceTest {
     private static final String TEST_PACKAGE = "package1";
     private static final String[] TEST_PACKAGES = new String[] { TEST_PACKAGE };
+    private static final int WORKER_THREAD_TIMEOUT_MILLISECONDS = 1;
 
     @Mock Context mContext;
     @Mock IBackupManagerMonitor mBackupManagerMonitor;
@@ -179,6 +181,7 @@
 
         mService.agentDisconnected("com.android.foo");
 
+        mService.waitForAsyncOperation();
         verify(mOperationStorage).cancelOperation(eq(123), eq(true), any(IntConsumer.class));
         verify(mOperationStorage).cancelOperation(eq(456), eq(true), any());
         verify(mOperationStorage).cancelOperation(eq(789), eq(true), any());
@@ -207,6 +210,8 @@
         boolean isEnabledStatePersisted = false;
         boolean shouldUseNewBackupEligibilityRules = false;
 
+        private volatile Thread mWorkerThread = null;
+
         TestBackupService(Context context, PackageManager packageManager,
                 LifecycleOperationStorage operationStorage) {
             super(context, packageManager, operationStorage);
@@ -229,5 +234,23 @@
         boolean shouldUseNewBackupEligibilityRules() {
             return shouldUseNewBackupEligibilityRules;
         }
+
+        @Override
+        Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
+            mWorkerThread = super.getThreadForAsyncOperation(operationName, operation);
+            return mWorkerThread;
+        }
+
+        private void waitForAsyncOperation() {
+            if (mWorkerThread == null) {
+                return;
+            }
+
+            try {
+                mWorkerThread.join(/* millis */ WORKER_THREAD_TIMEOUT_MILLISECONDS);
+            } catch (InterruptedException e) {
+                fail("Failed waiting for worker thread to complete: " + e.getMessage());
+            }
+        }
     }
 }
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 79ab009..5179bab 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -27,7 +27,6 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
-import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import java.io.PrintWriter;
@@ -195,57 +194,20 @@
     }
 
     /**
-     * Convert display name source to string.
+     * Convert mobile data policy to string.
      *
-     * @param source The display name source.
-     * @return The display name source in string format.
+     * @param mobileDataPolicy The mobile data policy.
+     * @return The mobile data policy in string format.
      */
-    @NonNull
-    public static String displayNameSourceToString(
-            @SubscriptionManager.SimDisplayNameSource int source) {
-        switch (source) {
-            case SubscriptionManager.NAME_SOURCE_UNKNOWN: return "UNKNOWN";
-            case SubscriptionManager.NAME_SOURCE_CARRIER_ID: return "CARRIER_ID";
-            case SubscriptionManager.NAME_SOURCE_SIM_SPN: return "SIM_SPN";
-            case SubscriptionManager.NAME_SOURCE_USER_INPUT: return "USER_INPUT";
-            case SubscriptionManager.NAME_SOURCE_CARRIER: return "CARRIER";
-            case SubscriptionManager.NAME_SOURCE_SIM_PNN: return "SIM_PNN";
+    public static @NonNull String mobileDataPolicyToString(
+            @TelephonyManager.MobileDataPolicy int mobileDataPolicy) {
+        switch (mobileDataPolicy) {
+            case TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL:
+                return "DATA_ON_NON_DEFAULT_DURING_VOICE_CALL";
+            case TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED:
+                return "MMS_ALWAYS_ALLOWED";
             default:
-                return "UNKNOWN(" + source + ")";
-        }
-    }
-
-    /**
-     * Convert subscription type to string.
-     *
-     * @param type The subscription type.
-     * @return The subscription type in string format.
-     */
-    @NonNull
-    public static String subscriptionTypeToString(@SubscriptionManager.SubscriptionType int type) {
-        switch (type) {
-            case SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM: return "LOCAL_SIM";
-            case SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM: return "REMOTE_SIM";
-            default:
-                return "UNKNOWN(" + type + ")";
-        }
-    }
-
-    /**
-     * Convert usage setting to string.
-     *
-     * @param usageSetting Usage setting.
-     * @return The usage setting in string format.
-     */
-    @NonNull
-    public static String usageSettingToString(@SubscriptionManager.UsageSetting int usageSetting) {
-        switch (usageSetting) {
-            case SubscriptionManager.USAGE_SETTING_UNKNOWN: return "UNKNOWN";
-            case SubscriptionManager.USAGE_SETTING_DEFAULT: return "DEFAULT";
-            case SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC: return "VOICE_CENTRIC";
-            case SubscriptionManager.USAGE_SETTING_DATA_CENTRIC: return "DATA_CENTRIC";
-            default:
-                return "UNKNOWN(" + usageSetting + ")";
+                return "UNKNOWN(" + mobileDataPolicy + ")";
         }
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 0d3c80f..e055f63 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -974,7 +974,7 @@
                 + " groupOwner=" + mGroupOwner
                 + " isGroupDisabled=" + mIsGroupDisabled
                 + " displayNameSource="
-                + TelephonyUtils.displayNameSourceToString(mDisplayNameSource)
+                + SubscriptionManager.displayNameSourceToString(mDisplayNameSource)
                 + " iconTint=" + mIconTint
                 + " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber)
                 + " dataRoaming=" + mDataRoaming
@@ -988,9 +988,9 @@
                 + " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules)
                 + " countryIso=" + mCountryIso
                 + " profileClass=" + mProfileClass
-                + " mType=" + TelephonyUtils.subscriptionTypeToString(mType)
+                + " mType=" + SubscriptionManager.subscriptionTypeToString(mType)
                 + " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled
-                + " usageSetting=" + TelephonyUtils.usageSettingToString(mUsageSetting)
+                + " usageSetting=" + SubscriptionManager.usageSettingToString(mUsageSetting)
                 + "]";
     }
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 6189b49..e6c6b62 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -4092,4 +4092,65 @@
                 (iSub)-> iSub.setUsageSetting(
                         usageSetting, subscriptionId, mContext.getOpPackageName()));
     }
+
+    /**
+     * Convert display name source to string.
+     *
+     * @param source The display name source.
+     * @return The display name source in string format.
+     *
+     * @hide
+     */
+    @NonNull
+    public static String displayNameSourceToString(
+            @SubscriptionManager.SimDisplayNameSource int source) {
+        switch (source) {
+            case SubscriptionManager.NAME_SOURCE_UNKNOWN: return "UNKNOWN";
+            case SubscriptionManager.NAME_SOURCE_CARRIER_ID: return "CARRIER_ID";
+            case SubscriptionManager.NAME_SOURCE_SIM_SPN: return "SIM_SPN";
+            case SubscriptionManager.NAME_SOURCE_USER_INPUT: return "USER_INPUT";
+            case SubscriptionManager.NAME_SOURCE_CARRIER: return "CARRIER";
+            case SubscriptionManager.NAME_SOURCE_SIM_PNN: return "SIM_PNN";
+            default:
+                return "UNKNOWN(" + source + ")";
+        }
+    }
+
+    /**
+     * Convert subscription type to string.
+     *
+     * @param type The subscription type.
+     * @return The subscription type in string format.
+     *
+     * @hide
+     */
+    @NonNull
+    public static String subscriptionTypeToString(@SubscriptionManager.SubscriptionType int type) {
+        switch (type) {
+            case SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM: return "LOCAL_SIM";
+            case SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM: return "REMOTE_SIM";
+            default:
+                return "UNKNOWN(" + type + ")";
+        }
+    }
+
+    /**
+     * Convert usage setting to string.
+     *
+     * @param usageSetting Usage setting.
+     * @return The usage setting in string format.
+     *
+     * @hide
+     */
+    @NonNull
+    public static String usageSettingToString(@SubscriptionManager.UsageSetting int usageSetting) {
+        switch (usageSetting) {
+            case SubscriptionManager.USAGE_SETTING_UNKNOWN: return "UNKNOWN";
+            case SubscriptionManager.USAGE_SETTING_DEFAULT: return "DEFAULT";
+            case SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC: return "VOICE_CENTRIC";
+            case SubscriptionManager.USAGE_SETTING_DATA_CENTRIC: return "DATA_CENTRIC";
+            default:
+                return "UNKNOWN(" + usageSetting + ")";
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e658c2e..caee4e2 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -72,6 +72,7 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "WIFI_MODE_", value = {
+            WIFI_MODE_UNKNOWN,
             WIFI_MODE_WIFI_ONLY,
             WIFI_MODE_CELLULAR_PREFERRED,
             WIFI_MODE_WIFI_PREFERRED
@@ -79,6 +80,12 @@
     public @interface WiFiCallingMode {}
 
     /**
+     * Wifi calling mode is unknown. This is for initialization only.
+     * @hide
+     */
+    public static final int WIFI_MODE_UNKNOWN = -1;
+
+    /**
      * Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
      * registration if signal quality degrades.
      */
@@ -1573,4 +1580,24 @@
                         .get());
         return binder;
     }
+
+    /**
+     * Convert Wi-Fi calling mode to string.
+     *
+     * @param mode Wi-Fi calling mode.
+     * @return The Wi-Fi calling mode in string format.
+     *
+     * @hide
+     */
+    @NonNull
+    public static String wifiCallingModeToString(@ImsMmTelManager.WiFiCallingMode int mode) {
+        switch (mode) {
+            case ImsMmTelManager.WIFI_MODE_UNKNOWN: return "UNKNOWN";
+            case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: return "WIFI_ONLY";
+            case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: return "CELLULAR_PREFERRED";
+            case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: return "WIFI_PREFERRED";
+            default:
+                return "UNKNOWN(" + mode + ")";
+        }
+    }
 }
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 03eb462..d91aa1e 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -13,8 +13,6 @@
         <option name="run-command" value="cmd window tracing level all" />
         <!-- set WM tracing to frame (avoid incomplete states) -->
         <option name="run-command" value="cmd window tracing frame" />
-        <!-- set Layer tracing buffer size to 50mb -->
-        <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 51200" />
         <!-- ensure lock screen mode is swipe -->
         <option name="run-command" value="locksettings set-disabled false" />
         <!-- restart launcher to activate TAPL -->