Merge "Update the split screen APIs used by the launcher" into sc-dev
diff --git a/Android.bp b/Android.bp
index 908280e..9374c01 100644
--- a/Android.bp
+++ b/Android.bp
@@ -421,6 +421,7 @@
         ":resourcemanager_aidl",
         ":storaged_aidl",
         ":vold_aidl",
+        ":deviceproductinfoconstants_aidl",
 
         // For the generated R.java and Manifest.java
         ":framework-res{.aapt.srcjar}",
@@ -580,9 +581,11 @@
         "android.hardware.vibrator-V1.1-java",
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
+        "android.hardware.vibrator-V2-java",
         "android.security.apc-java",
         "android.security.authorization-java",
         "android.security.usermanager-java",
+        "android.security.vpnprofilestore-java",
         "android.system.keystore2-V1-java",
         "android.system.suspend.control.internal-java",
         "cameraprotosnano",
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
index e83c64c..5a45961 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
@@ -44,7 +44,7 @@
 @RunWith(AndroidJUnit4.class)
 public class TypefaceCreatePerfTest {
     // A font file name in asset directory.
-    private static final String TEST_FONT_NAME = "DancingScript-Regular.ttf";
+    private static final String TEST_FONT_NAME = "DancingScript.ttf";
 
     @Rule
     public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index 1d94d7e..d5ed95f 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -97,11 +97,21 @@
     private val state: BenchmarkState get() = perfStatusReporter.benchmarkState
     private val apks: List<File> get() = params.apks
 
+    private fun safeParse(parser: ParallelParser<*>, file: File) {
+        try {
+            parser.parse(file)
+        } catch (e: Exception) {
+            // ignore
+        }
+    }
+
     @Test
     fun sequentialNoCache() {
         params.cacheDirToParser(null).use { parser ->
             while (state.keepRunning()) {
-                apks.forEach { parser.parse(it) }
+                apks.forEach {
+                    safeParse(parser, it)
+                }
             }
         }
     }
@@ -110,10 +120,10 @@
     fun sequentialCached() {
         params.cacheDirToParser(testFolder.newFolder()).use { parser ->
             // Fill the cache
-            apks.forEach { parser.parse(it) }
+            apks.forEach { safeParse(parser, it) }
 
             while (state.keepRunning()) {
-                apks.forEach { parser.parse(it) }
+                apks.forEach { safeParse(parser, it) }
             }
         }
     }
@@ -132,7 +142,7 @@
     fun parallelCached() {
         params.cacheDirToParser(testFolder.newFolder()).use { parser ->
             // Fill the cache
-            apks.forEach { parser.parse(it) }
+            apks.forEach { safeParse(parser, it) }
 
             while (state.keepRunning()) {
                 apks.forEach { parser.submit(it) }
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index df690d0..b1b733a 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -108,6 +108,8 @@
      * @hide
      */
     public static final int REASON_DENIED = -1;
+
+    /* Reason code range 0-9 are reserved for default reasons */
     /**
      * The default reason code if reason is unknown.
      */
@@ -116,6 +118,8 @@
      * Use REASON_OTHER if there is no better choice.
      */
     public static final int REASON_OTHER = 1;
+
+    /* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */
     /** @hide */
     public static final int REASON_PROC_STATE_PERSISTENT = 10;
     /** @hide */
@@ -128,6 +132,8 @@
     public static final int REASON_PROC_STATE_FGS = 14;
     /** @hide */
     public static final int REASON_PROC_STATE_BFGS = 15;
+
+    /* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */
     /** @hide */
     public static final int REASON_UID_VISIBLE = 50;
     /** @hide */
@@ -166,114 +172,126 @@
     public static final int REASON_EXEMPTED_PACKAGE = 64;
     /** @hide */
     public static final int REASON_ALLOWLISTED_PACKAGE  = 65;
-    /**
-     * If it's because of a role,
-     * @hide
-     */
+    /** @hide */
     public static final int REASON_APPOP = 66;
 
     /* BG-FGS-launch is allowed by temp-allowlist or system-allowlist.
-    Reason code for temp and system allowlist starts here.
-    */
+       Reason code for temp and system allowlist starts here.
+       Reason code range 100-199 are reserved for public reasons. */
+    /**
+     * Set temp-allowlist for location geofence purpose.
+     */
     public static final int REASON_GEOFENCING = 100;
+    /**
+     * Set temp-allowlist for server push messaging.
+     */
     public static final int REASON_PUSH_MESSAGING = 101;
-    public static final int REASON_ACTIVITY_RECOGNITION = 102;
+    /**
+     * Set temp-allowlist for server push messaging over the quota.
+     */
+    public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102;
+    /**
+     * Set temp-allowlist for activity recognition.
+     */
+    public static final int REASON_ACTIVITY_RECOGNITION = 103;
 
+    /* Reason code range 200-299 are reserved for broadcast actions */
     /**
      * Broadcast ACTION_BOOT_COMPLETED.
      * @hide
      */
-    public static final int REASON_BOOT_COMPLETED = 103;
+    public static final int REASON_BOOT_COMPLETED = 200;
     /**
      * Broadcast ACTION_PRE_BOOT_COMPLETED.
      * @hide
      */
-    public static final int REASON_PRE_BOOT_COMPLETED = 104;
-
+    public static final int REASON_PRE_BOOT_COMPLETED = 201;
     /**
      * Broadcast ACTION_LOCKED_BOOT_COMPLETED.
      * @hide
      */
-    public static final int REASON_LOCKED_BOOT_COMPLETED = 105;
+    public static final int REASON_LOCKED_BOOT_COMPLETED = 202;
+
+    /* Reason code range 300-399 are reserved for other internal reasons */
     /**
      * Device idle system allowlist, including EXCEPT-IDLE
      * @hide
      */
-    public static final int REASON_SYSTEM_ALLOW_LISTED  = 106;
+    public static final int REASON_SYSTEM_ALLOW_LISTED  = 300;
     /** @hide */
-    public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 107;
+    public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
     /**
      * AlarmManagerService.
      * @hide
      */
-    public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 108;
+    public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 302;
     /**
      * ActiveServices.
      * @hide
      */
-    public static final int REASON_SERVICE_LAUNCH = 109;
+    public static final int REASON_SERVICE_LAUNCH = 303;
     /**
      * KeyChainSystemService.
      * @hide
      */
-    public static final int REASON_KEY_CHAIN = 110;
+    public static final int REASON_KEY_CHAIN = 304;
     /**
      * PackageManagerService.
      * @hide
      */
-    public static final int REASON_PACKAGE_VERIFIER = 111;
+    public static final int REASON_PACKAGE_VERIFIER = 305;
     /**
      * SyncManager.
      * @hide
      */
-    public static final int REASON_SYNC_MANAGER = 112;
+    public static final int REASON_SYNC_MANAGER = 306;
     /**
      * DomainVerificationProxyV1.
      * @hide
      */
-    public static final int REASON_DOMAIN_VERIFICATION_V1 = 113;
+    public static final int REASON_DOMAIN_VERIFICATION_V1 = 307;
     /**
      * DomainVerificationProxyV2.
      * @hide
      */
-    public static final int REASON_DOMAIN_VERIFICATION_V2 = 114;
+    public static final int REASON_DOMAIN_VERIFICATION_V2 = 308;
     /** @hide */
-    public static final int REASON_VPN = 115;
+    public static final int REASON_VPN = 309;
     /**
      * NotificationManagerService.
      * @hide
      */
-    public static final int REASON_NOTIFICATION_SERVICE = 116;
+    public static final int REASON_NOTIFICATION_SERVICE = 310;
     /**
      * Broadcast ACTION_MY_PACKAGE_REPLACED.
      * @hide
      */
-    public static final int REASON_PACKAGE_REPLACED = 117;
+    public static final int REASON_PACKAGE_REPLACED = 311;
     /**
      * LocationProviderManager.
      * @hide
      */
-    public static final int REASON_LOCATION_PROVIDER = 118;
+    public static final int REASON_LOCATION_PROVIDER = 312;
     /**
      * MediaButtonReceiver.
      * @hide
      */
-    public static final int REASON_MEDIA_BUTTON = 119;
+    public static final int REASON_MEDIA_BUTTON = 313;
     /**
      * InboundSmsHandler.
      * @hide
      */
-    public static final int REASON_EVENT_SMS = 120;
+    public static final int REASON_EVENT_SMS = 314;
     /**
      * InboundSmsHandler.
      * @hide
      */
-    public static final int REASON_EVENT_MMS = 121;
+    public static final int REASON_EVENT_MMS = 315;
     /**
      * Shell app.
      * @hide
      */
-    public static final int REASON_SHELL = 122;
+    public static final int REASON_SHELL = 316;
 
     /**
      * The list of BG-FGS-Launch and temp-allowlist reason code.
@@ -310,6 +328,7 @@
             // temp and system allowlist reasons.
             REASON_GEOFENCING,
             REASON_PUSH_MESSAGING,
+            REASON_PUSH_MESSAGING_OVER_QUOTA,
             REASON_ACTIVITY_RECOGNITION,
             REASON_BOOT_COMPLETED,
             REASON_PRE_BOOT_COMPLETED,
@@ -589,6 +608,8 @@
                 return "GEOFENCING";
             case REASON_PUSH_MESSAGING:
                 return "PUSH_MESSAGING";
+            case REASON_PUSH_MESSAGING_OVER_QUOTA:
+                return "PUSH_MESSAGING_OVER_QUOTA";
             case REASON_ACTIVITY_RECOGNITION:
                 return "ACTIVITY_RECOGNITION";
             case REASON_BOOT_COMPLETED:
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index ea73369..2b2918c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -28,6 +28,8 @@
 import static android.app.AlarmManager.RTC;
 import static android.app.AlarmManager.RTC_WAKEUP;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
 import static android.os.UserHandle.USER_SYSTEM;
 
@@ -524,10 +526,12 @@
             if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
                 mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
 
-                mOptsWithFgs.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);
-                mOptsWithoutFgs.setTemporaryAppWhitelistDuration(
+                mOptsWithFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                        REASON_ALARM_MANAGER_WHILE_IDLE, "");
+                mOptsWithoutFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
                         TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
-                        ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+                        REASON_ALARM_MANAGER_WHILE_IDLE, "");
             }
         }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
index 34ba753b3..862d8b7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
@@ -25,7 +25,9 @@
 public interface JobCompletedListener {
     /**
      * Callback for when a job is completed.
+     *
+     * @param stopReason      The stop reason provided to JobParameters.
      * @param needsReschedule Whether the implementing class should reschedule this job.
      */
-    void onJobCompletedLocked(JobStatus jobStatus, boolean needsReschedule);
+    void onJobCompletedLocked(JobStatus jobStatus, int stopReason, boolean needsReschedule);
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index af97715..0308d68 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -73,20 +73,48 @@
             CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
     private static final long DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS = 30_000;
 
-    // Try to give higher priority types lower values.
+    /**
+     * Set of possible execution types that a job can have. The actual type(s) of a job are based
+     * on the {@link JobStatus#lastEvaluatedPriority}, which is typically evaluated right before
+     * execution (when we're trying to determine which jobs to run next) and won't change after the
+     * job has started executing.
+     *
+     * Try to give higher priority types lower values.
+     *
+     * @see #getJobWorkTypes(JobStatus)
+     */
+
+    /** Job shouldn't run or qualify as any other work type. */
     static final int WORK_TYPE_NONE = 0;
+    /** The job is for an app in the TOP state for a currently active user. */
     static final int WORK_TYPE_TOP = 1 << 0;
-    static final int WORK_TYPE_EJ = 1 << 1;
-    static final int WORK_TYPE_BG = 1 << 2;
-    static final int WORK_TYPE_BGUSER = 1 << 3;
+    /**
+     * The job is for an app in a {@link ActivityManager#PROCESS_STATE_FOREGROUND_SERVICE} or higher
+     * state (excluding {@link ActivityManager#PROCESS_STATE_TOP} for a currently active user.
+     */
+    static final int WORK_TYPE_FGS = 1 << 1;
+    /** The job is allowed to run as an expedited job for a currently active user. */
+    static final int WORK_TYPE_EJ = 1 << 2;
+    /**
+     * The job does not satisfy any of the conditions for {@link #WORK_TYPE_TOP},
+     * {@link #WORK_TYPE_FGS}, or {@link #WORK_TYPE_EJ}, but is for a currently active user, so
+     * can run as a background job.
+     */
+    static final int WORK_TYPE_BG = 1 << 3;
+    /**
+     * The job does not satisfy any of the conditions for {@link #WORK_TYPE_TOP},
+     * {@link #WORK_TYPE_FGS}, or {@link #WORK_TYPE_EJ}, but is for a completely background user,
+     * so can run as a background user job.
+     */
+    static final int WORK_TYPE_BGUSER = 1 << 4;
     @VisibleForTesting
-    static final int NUM_WORK_TYPES = 4;
-    private static final int ALL_WORK_TYPES =
-            WORK_TYPE_TOP | WORK_TYPE_EJ | WORK_TYPE_BG | WORK_TYPE_BGUSER;
+    static final int NUM_WORK_TYPES = 5;
+    private static final int ALL_WORK_TYPES = (1 << NUM_WORK_TYPES) - 1;
 
     @IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
             WORK_TYPE_NONE,
             WORK_TYPE_TOP,
+            WORK_TYPE_FGS,
             WORK_TYPE_EJ,
             WORK_TYPE_BG,
             WORK_TYPE_BGUSER
@@ -95,12 +123,15 @@
     public @interface WorkType {
     }
 
-    private static String workTypeToString(@WorkType int workType) {
+    @VisibleForTesting
+    static String workTypeToString(@WorkType int workType) {
         switch (workType) {
             case WORK_TYPE_NONE:
                 return "NONE";
             case WORK_TYPE_TOP:
                 return "TOP";
+            case WORK_TYPE_FGS:
+                return "FGS";
             case WORK_TYPE_EJ:
                 return "EJ";
             case WORK_TYPE_BG:
@@ -131,58 +162,60 @@
             new WorkConfigLimitsPerMemoryTrimLevel(
                     new WorkTypeConfig("screen_on_normal", 11,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_EJ, 3),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
                     ),
                     new WorkTypeConfig("screen_on_moderate", 9,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 2),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
                     ),
                     new WorkTypeConfig("screen_on_low", 6,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1),
-                                    Pair.create(WORK_TYPE_BG, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     ),
-                    new WorkTypeConfig("screen_on_critical", 5,
+                    new WorkTypeConfig("screen_on_critical", 6,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     )
             );
     private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
             new WorkConfigLimitsPerMemoryTrimLevel(
-                    new WorkTypeConfig("screen_off_normal", 13,
+                    new WorkTypeConfig("screen_off_normal", 15,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2),
+                                    Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
                     ),
-                    new WorkTypeConfig("screen_off_moderate", 13,
+                    new WorkTypeConfig("screen_off_moderate", 15,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_EJ, 3),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_FGS, 2),
+                                    Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
                     ),
-                    new WorkTypeConfig("screen_off_low", 7,
+                    new WorkTypeConfig("screen_off_low", 9,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 2),
-                                    Pair.create(WORK_TYPE_BG, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     ),
-                    new WorkTypeConfig("screen_off_critical", 5,
+                    new WorkTypeConfig("screen_off_critical", 6,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     )
@@ -753,13 +786,22 @@
             return null;
         }
 
+        // We're over the minimum guaranteed runtime. Stop the job if we're over config limits,
+        // there are pending jobs that could replace this one, or the device state is not conducive
+        // to long runs.
+
+        if (mPowerManager.isPowerSaveMode()) {
+            return "battery saver";
+        }
+        if (mPowerManager.isDeviceIdleMode()) {
+            return "deep doze";
+        }
+
         // Update config in case memory usage has changed significantly.
         updateCounterConfigLocked();
 
         @WorkType final int workType = context.getRunningJobWorkType();
 
-        // We're over the minimum guaranteed runtime. Stop the job if we're over config limits or
-        // there are pending jobs that could replace this one.
         if (mRunningJobs.size() > mWorkTypeConfig.getMaxTotal()
                 || mWorkCountTracker.isOverTypeLimit(workType)) {
             return "too many jobs running";
@@ -786,13 +828,6 @@
                     return "blocking " + workTypeToString(workType) + " queue";
                 }
             }
-
-            if (mPowerManager.isPowerSaveMode()) {
-                return "battery saver";
-            }
-            if (mPowerManager.isDeviceIdleMode()) {
-                return "deep doze";
-            }
         }
 
         // Easy check. If there are pending jobs of the same work type, then we know that
@@ -975,10 +1010,11 @@
 
     int getJobWorkTypes(@NonNull JobStatus js) {
         int classification = 0;
-        // TODO: create dedicated work type for FGS
         if (shouldRunAsFgUserJob(js)) {
             if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
                 classification |= WORK_TYPE_TOP;
+            } else if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_FOREGROUND_SERVICE) {
+                classification |= WORK_TYPE_FGS;
             } else {
                 classification |= WORK_TYPE_BG;
             }
@@ -999,11 +1035,13 @@
         private static final String KEY_PREFIX_MAX_TOTAL =
                 CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
         private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
+        private static final String KEY_PREFIX_MAX_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "max_fgs_";
         private static final String KEY_PREFIX_MAX_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "max_ej_";
         private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
         private static final String KEY_PREFIX_MAX_BGUSER =
                 CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
         private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
+        private static final String KEY_PREFIX_MIN_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "min_fgs_";
         private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_";
         private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
         private static final String KEY_PREFIX_MIN_BGUSER =
@@ -1051,6 +1089,10 @@
                     properties.getInt(KEY_PREFIX_MAX_TOP + mConfigIdentifier,
                             mDefaultMaxAllowedSlots.get(WORK_TYPE_TOP, mMaxTotal))));
             mMaxAllowedSlots.put(WORK_TYPE_TOP, maxTop);
+            final int maxFgs = Math.max(1, Math.min(mMaxTotal,
+                    properties.getInt(KEY_PREFIX_MAX_FGS + mConfigIdentifier,
+                            mDefaultMaxAllowedSlots.get(WORK_TYPE_FGS, mMaxTotal))));
+            mMaxAllowedSlots.put(WORK_TYPE_FGS, maxFgs);
             final int maxEj = Math.max(1, Math.min(mMaxTotal,
                     properties.getInt(KEY_PREFIX_MAX_EJ + mConfigIdentifier,
                             mDefaultMaxAllowedSlots.get(WORK_TYPE_EJ, mMaxTotal))));
@@ -1072,6 +1114,12 @@
                             mDefaultMinReservedSlots.get(WORK_TYPE_TOP))));
             mMinReservedSlots.put(WORK_TYPE_TOP, minTop);
             remaining -= minTop;
+            // Ensure fgs is in the range [0, min(maxFgs, remaining)]
+            final int minFgs = Math.max(0, Math.min(Math.min(maxFgs, remaining),
+                    properties.getInt(KEY_PREFIX_MIN_FGS + mConfigIdentifier,
+                            mDefaultMinReservedSlots.get(WORK_TYPE_FGS))));
+            mMinReservedSlots.put(WORK_TYPE_FGS, minFgs);
+            remaining -= minFgs;
             // Ensure ej is in the range [0, min(maxEj, remaining)]
             final int minEj = Math.max(0, Math.min(Math.min(maxEj, remaining),
                     properties.getInt(KEY_PREFIX_MIN_EJ + mConfigIdentifier,
@@ -1109,6 +1157,10 @@
                     .println();
             pw.print(KEY_PREFIX_MAX_TOP + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_TOP))
                     .println();
+            pw.print(KEY_PREFIX_MIN_FGS + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_FGS))
+                    .println();
+            pw.print(KEY_PREFIX_MAX_FGS + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_FGS))
+                    .println();
             pw.print(KEY_PREFIX_MIN_EJ + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_EJ))
                     .println();
             pw.print(KEY_PREFIX_MAX_EJ + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_EJ))
@@ -1203,6 +1255,7 @@
         private int mConfigMaxTotal;
         private final SparseIntArray mConfigNumReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
         private final SparseIntArray mConfigAbsoluteMaxSlots = new SparseIntArray(NUM_WORK_TYPES);
+        private final SparseIntArray mRecycledReserved = new SparseIntArray(NUM_WORK_TYPES);
 
         /**
          * Numbers may be lower in this than in {@link #mConfigNumReservedSlots} if there aren't
@@ -1218,11 +1271,14 @@
             mConfigMaxTotal = workTypeConfig.getMaxTotal();
             mConfigNumReservedSlots.put(WORK_TYPE_TOP,
                     workTypeConfig.getMinReserved(WORK_TYPE_TOP));
+            mConfigNumReservedSlots.put(WORK_TYPE_FGS,
+                    workTypeConfig.getMinReserved(WORK_TYPE_FGS));
             mConfigNumReservedSlots.put(WORK_TYPE_EJ, workTypeConfig.getMinReserved(WORK_TYPE_EJ));
             mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
             mConfigNumReservedSlots.put(WORK_TYPE_BGUSER,
                     workTypeConfig.getMinReserved(WORK_TYPE_BGUSER));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
+            mConfigAbsoluteMaxSlots.put(WORK_TYPE_FGS, workTypeConfig.getMax(WORK_TYPE_FGS));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_EJ, workTypeConfig.getMax(WORK_TYPE_EJ));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER));
@@ -1258,15 +1314,10 @@
                 // We don't need to adjust reservations if only one work type was modified
                 // because that work type is the one we're using.
 
-                // 0 is WORK_TYPE_NONE.
-                int workType = 1;
-                int rem = workTypes;
-                while (rem > 0) {
-                    if ((rem & 1) != 0) {
+                for (int workType = 1; workType <= workTypes; workType <<= 1) {
+                    if ((workType & workTypes) == workType) {
                         maybeAdjustReservations(workType);
                     }
-                    rem = rem >>> 1;
-                    workType = workType << 1;
                 }
             }
         }
@@ -1278,21 +1329,11 @@
             int numAdj = 0;
             // We don't know which type we'll classify the job as when we run it yet, so make sure
             // we have space in all applicable slots.
-            if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
-                mNumPendingJobs.put(WORK_TYPE_TOP, mNumPendingJobs.get(WORK_TYPE_TOP) + adj);
-                numAdj++;
-            }
-            if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
-                mNumPendingJobs.put(WORK_TYPE_EJ, mNumPendingJobs.get(WORK_TYPE_EJ) + adj);
-                numAdj++;
-            }
-            if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
-                mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + adj);
-                numAdj++;
-            }
-            if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
-                mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + adj);
-                numAdj++;
+            for (int workType = 1; workType <= workTypes; workType <<= 1) {
+                if ((workTypes & workType) == workType) {
+                    mNumPendingJobs.put(workType, mNumPendingJobs.get(workType) + adj);
+                    numAdj++;
+                }
             }
 
             return numAdj;
@@ -1386,105 +1427,45 @@
             mNumUnspecializedRemaining = mConfigMaxTotal;
 
             // Step 1
-            int runTop = mNumRunningJobs.get(WORK_TYPE_TOP);
-            int resTop = runTop;
-            mNumUnspecializedRemaining -= resTop;
-            int runEj = mNumRunningJobs.get(WORK_TYPE_EJ);
-            int resEj = runEj;
-            mNumUnspecializedRemaining -= resEj;
-            int runBg = mNumRunningJobs.get(WORK_TYPE_BG);
-            int resBg = runBg;
-            mNumUnspecializedRemaining -= resBg;
-            int runBgUser = mNumRunningJobs.get(WORK_TYPE_BGUSER);
-            int resBgUser = runBgUser;
-            mNumUnspecializedRemaining -= resBgUser;
+            for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+                int run = mNumRunningJobs.get(workType);
+                mRecycledReserved.put(workType, run);
+                mNumUnspecializedRemaining -= run;
+            }
 
             // Step 2
-            final int numTop = runTop + mNumPendingJobs.get(WORK_TYPE_TOP);
-            int fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numTop, mConfigNumReservedSlots.get(WORK_TYPE_TOP) - resTop)));
-            resTop += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
-            final int numEj = runEj + mNumPendingJobs.get(WORK_TYPE_EJ);
-            fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numEj, mConfigNumReservedSlots.get(WORK_TYPE_EJ) - resEj)));
-            resEj += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
-            final int numBg = runBg + mNumPendingJobs.get(WORK_TYPE_BG);
-            fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numBg, mConfigNumReservedSlots.get(WORK_TYPE_BG) - resBg)));
-            resBg += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
-            final int numBgUser = runBgUser + mNumPendingJobs.get(WORK_TYPE_BGUSER);
-            fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numBgUser,
-                            mConfigNumReservedSlots.get(WORK_TYPE_BGUSER) - resBgUser)));
-            resBgUser += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
+            for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+                int num = mNumRunningJobs.get(workType) + mNumPendingJobs.get(workType);
+                int res = mRecycledReserved.get(workType);
+                int fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
+                        Math.min(num, mConfigNumReservedSlots.get(workType) - res)));
+                res += fillUp;
+                mRecycledReserved.put(workType, res);
+                mNumUnspecializedRemaining -= fillUp;
+            }
 
             // Step 3
-            int unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP), numTop) - resTop));
-            mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
-
-            unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_EJ), numEj) - resEj));
-            mNumActuallyReservedSlots.put(WORK_TYPE_EJ, resEj + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
-
-            unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
-            mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
-
-            unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER), numBgUser)
-                                    - resBgUser));
-            mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
+            for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+                int num = mNumRunningJobs.get(workType) + mNumPendingJobs.get(workType);
+                int res = mRecycledReserved.get(workType);
+                int unspecializedAssigned = Math.max(0,
+                        Math.min(mNumUnspecializedRemaining,
+                                Math.min(mConfigAbsoluteMaxSlots.get(workType), num) - res));
+                mNumActuallyReservedSlots.put(workType, res + unspecializedAssigned);
+                mNumUnspecializedRemaining -= unspecializedAssigned;
+            }
         }
 
         int canJobStart(int workTypes) {
-            if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_TOP) + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_TOP) + mNumStartingJobs.get(WORK_TYPE_TOP)
-                        < maxAllowed) {
-                    return WORK_TYPE_TOP;
-                }
-            }
-            if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_EJ),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_EJ) + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_EJ) + mNumStartingJobs.get(WORK_TYPE_EJ)
-                        < maxAllowed) {
-                    return WORK_TYPE_EJ;
-                }
-            }
-            if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_BG) + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_BG) + mNumStartingJobs.get(WORK_TYPE_BG)
-                        < maxAllowed) {
-                    return WORK_TYPE_BG;
-                }
-            }
-            if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_BGUSER)
-                                + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_BGUSER) + mNumStartingJobs.get(WORK_TYPE_BGUSER)
-                        < maxAllowed) {
-                    return WORK_TYPE_BGUSER;
+            for (int workType = 1; workType <= workTypes; workType <<= 1) {
+                if ((workTypes & workType) == workType) {
+                    final int maxAllowed = Math.min(
+                            mConfigAbsoluteMaxSlots.get(workType),
+                            mNumActuallyReservedSlots.get(workType) + mNumUnspecializedRemaining);
+                    if (mNumRunningJobs.get(workType) + mNumStartingJobs.get(workType)
+                            < maxAllowed) {
+                        return workType;
+                    }
                 }
             }
             return WORK_TYPE_NONE;
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 040a116..515cb74 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1745,11 +1745,12 @@
      * A job just finished executing. We fetch the
      * {@link com.android.server.job.controllers.JobStatus} from the store and depending on
      * whether we want to reschedule we re-add it to the controllers.
-     * @param jobStatus Completed job.
+     *
+     * @param jobStatus       Completed job.
      * @param needsReschedule Whether the implementing class should reschedule this job.
      */
     @Override
-    public void onJobCompletedLocked(JobStatus jobStatus, boolean needsReschedule) {
+    public void onJobCompletedLocked(JobStatus jobStatus, int stopReason, boolean needsReschedule) {
         if (DEBUG) {
             Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
         }
@@ -1767,6 +1768,11 @@
         // we stop it.
         final JobStatus rescheduledJob = needsReschedule
                 ? getRescheduleJobForFailureLocked(jobStatus) : null;
+        if (rescheduledJob != null
+                && (stopReason == JobParameters.REASON_TIMEOUT
+                || stopReason == JobParameters.REASON_PREEMPT)) {
+            rescheduledJob.disallowRunInBatterySaverAndDoze();
+        }
 
         // Do not write back immediately if this is a periodic job. The job may get lost if system
         // shuts down before it is added back.
@@ -2293,7 +2299,8 @@
     /** Returns the maximum amount of time this job could run for. */
     public long getMaxJobExecutionTimeMs(JobStatus job) {
         synchronized (mLock) {
-            return mQuotaController.getMaxJobExecutionTimeMsLocked(job);
+            return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked(job));
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 2a23d60..9673449 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -273,10 +273,12 @@
                     // another binding flag for that.
                     bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                             | Context.BIND_ALMOST_PERCEPTIBLE
-                            | Context.BIND_ALLOW_NETWORK_ACCESS;
+                            | Context.BIND_ALLOW_NETWORK_ACCESS
+                            | Context.BIND_NOT_APP_COMPONENT_USAGE;
                 } else {
                     bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
-                            | Context.BIND_NOT_PERCEPTIBLE;
+                            | Context.BIND_NOT_PERCEPTIBLE
+                            | Context.BIND_NOT_APP_COMPONENT_USAGE;
                 }
                 binding = mContext.bindServiceAsUser(intent, this, bindFlags,
                         UserHandle.of(job.getUserId()));
@@ -379,8 +381,8 @@
     }
 
     boolean isWithinExecutionGuaranteeTime() {
-        return mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis
-                < sElapsedRealtimeClock.millis();
+        return sElapsedRealtimeClock.millis()
+                < mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis;
     }
 
     @GuardedBy("mLock")
@@ -848,11 +850,12 @@
         }
         applyStoppedReasonLocked(reason);
         completedJob = mRunningJob;
-        mJobPackageTracker.noteInactive(completedJob, mParams.getStopReason(), reason);
+        final int stopReason = mParams.getStopReason();
+        mJobPackageTracker.noteInactive(completedJob, stopReason, reason);
         FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
                 completedJob.getSourceUid(), null, completedJob.getBatteryName(),
                 FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
-                mParams.getStopReason(), completedJob.getStandbyBucket(), completedJob.getJobId(),
+                stopReason, completedJob.getStandbyBucket(), completedJob.getJobId(),
                 completedJob.hasChargingConstraint(),
                 completedJob.hasBatteryNotLowConstraint(),
                 completedJob.hasStorageNotLowConstraint(),
@@ -863,7 +866,7 @@
                 completedJob.hasContentTriggerConstraint());
         try {
             mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(),
-                    mParams.getStopReason());
+                    stopReason);
         } catch (RemoteException e) {
             // Whatever.
         }
@@ -882,7 +885,7 @@
         service = null;
         mAvailable = true;
         removeOpTimeOutLocked();
-        mCompletedListener.onJobCompletedLocked(completedJob, reschedule);
+        mCompletedListener.onJobCompletedLocked(completedJob, stopReason, reschedule);
         mJobConcurrencyManager.onJobCompletedLocked(this, completedJob, workType);
     }
 
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 eaf8f4d..aa8d98c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -954,7 +954,7 @@
                     appBucket, sourceTag,
                     elapsedRuntimes.first, elapsedRuntimes.second,
                     lastSuccessfulRunTime, lastFailedRunTime,
-                    (rtcIsGood) ? null : rtcRuntimes, internalFlags);
+                    (rtcIsGood) ? null : rtcRuntimes, internalFlags, /* dynamicConstraints */ 0);
             return js;
         }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 192f5e6..79ef321 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -64,7 +64,7 @@
      * when the app is temp whitelisted or in the foreground.
      */
     private final ArraySet<JobStatus> mAllowInIdleJobs;
-    private final SparseBooleanArray mForegroundUids;
+    private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
     private final DeviceIdleUpdateFunctor mDeviceIdleUpdateFunctor;
     private final DeviceIdleJobsDelayHandler mHandler;
     private final PowerManager mPowerManager;
@@ -77,7 +77,6 @@
     private int[] mDeviceIdleWhitelistAppIds;
     private int[] mPowerSaveTempWhitelistAppIds;
 
-    // onReceive
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -120,6 +119,10 @@
         }
     };
 
+    /** Criteria for whether or not we should a job's rush evaluation when the device exits Doze. */
+    private final Predicate<JobStatus> mShouldRushEvaluation = (jobStatus) ->
+            jobStatus.isRequestedExpeditedJob() || mForegroundUids.get(jobStatus.getSourceUid());
+
     public DeviceIdleJobsController(JobSchedulerService service) {
         super(service);
 
@@ -133,7 +136,6 @@
                 mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds();
         mDeviceIdleUpdateFunctor = new DeviceIdleUpdateFunctor();
         mAllowInIdleJobs = new ArraySet<>();
-        mForegroundUids = new SparseBooleanArray();
         final IntentFilter filter = new IntentFilter();
         filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
         filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
@@ -156,14 +158,9 @@
                 mHandler.removeMessages(PROCESS_BACKGROUND_JOBS);
                 mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
             } else {
-                // When coming out of doze, process all foreground uids immediately, while others
-                // will be processed after a delay of 3 seconds.
-                for (int i = 0; i < mForegroundUids.size(); i++) {
-                    if (mForegroundUids.valueAt(i)) {
-                        mService.getJobStore().forEachJobForSourceUid(
-                                mForegroundUids.keyAt(i), mDeviceIdleUpdateFunctor);
-                    }
-                }
+                // When coming out of doze, process all foreground uids and EJs immediately,
+                // while others will be processed after a delay of 3 seconds.
+                mService.getJobStore().forEachJob(mShouldRushEvaluation, mDeviceIdleUpdateFunctor);
                 mHandler.sendEmptyMessageDelayed(PROCESS_BACKGROUND_JOBS, BACKGROUND_JOBS_DELAY);
             }
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 5bdeb38..bad8dc1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -91,6 +91,12 @@
     static final int CONSTRAINT_WITHIN_EXPEDITED_QUOTA = 1 << 23;    // Implicit constraint
     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
 
+    // The following set of dynamic constraints are for specific use cases (as explained in their
+    // relative naming and comments). Right now, they apply different constraints, which is fine,
+    // but if in the future, we have overlapping dynamic constraint sets, removing one constraint
+    // set may accidentally remove a constraint applied by another dynamic set.
+    // TODO: properly handle overlapping dynamic constraint sets
+
     /**
      * The additional set of dynamic constraints that must be met if the job's effective bucket is
      * {@link JobSchedulerService#RESTRICTED_INDEX}. Connectivity can be ignored if the job doesn't
@@ -103,6 +109,13 @@
                     | CONSTRAINT_IDLE;
 
     /**
+     * The additional set of dynamic constraints that must be met if this is an expedited job that
+     * had a long enough run while the device was Dozing or in battery saver.
+     */
+    private static final int DYNAMIC_EXPEDITED_DEFERRAL_CONSTRAINTS =
+            CONSTRAINT_DEVICE_NOT_DOZING | CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
+
+    /**
      * Standard media URIs that contain the media files that might be important to the user.
      * @see #mHasMediaBackupExemption
      */
@@ -426,7 +439,8 @@
     private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
             int sourceUserId, int standbyBucket, String tag, int numFailures,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
-            long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
+            long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags,
+            int dynamicConstraints) {
         this.job = job;
         this.callingUid = callingUid;
         this.standbyBucket = standbyBucket;
@@ -487,6 +501,7 @@
         }
         this.requiredConstraints = requiredConstraints;
         mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
+        addDynamicConstraints(dynamicConstraints);
         mReadyNotDozing = canRunInDoze();
         if (standbyBucket == RESTRICTED_INDEX) {
             addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
@@ -521,7 +536,7 @@
                 jobStatus.getSourceTag(), jobStatus.getNumFailures(),
                 jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
                 jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
-                jobStatus.getInternalFlags());
+                jobStatus.getInternalFlags(), jobStatus.mDynamicConstraints);
         mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
         if (jobStatus.mPersistedUtcTimes != null) {
             if (DEBUG) {
@@ -543,12 +558,12 @@
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
             long lastSuccessfulRunTime, long lastFailedRunTime,
             Pair<Long, Long> persistedExecutionTimesUTC,
-            int innerFlags) {
+            int innerFlags, int dynamicConstraints) {
         this(job, callingUid, sourcePkgName, sourceUserId,
                 standbyBucket,
                 sourceTag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
-                lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
+                lastSuccessfulRunTime, lastFailedRunTime, innerFlags, dynamicConstraints);
 
         // Only during initial inflation do we record the UTC-timebase execution bounds
         // read from the persistent store.  If we ever have to recreate the JobStatus on
@@ -572,7 +587,8 @@
                 rescheduling.getStandbyBucket(),
                 rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
                 newLatestRuntimeElapsedMillis,
-                lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
+                lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags(),
+                rescheduling.mDynamicConstraints);
     }
 
     /**
@@ -609,7 +625,7 @@
                 standbyBucket, tag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
-                /*innerFlags=*/ 0);
+                /*innerFlags=*/ 0, /* dynamicConstraints */ 0);
     }
 
     public void enqueueWorkLocked(JobWorkItem work) {
@@ -1083,12 +1099,15 @@
      * in Doze.
      */
     public boolean canRunInDoze() {
-        return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0 || shouldTreatAsExpeditedJob();
+        return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0
+                || (shouldTreatAsExpeditedJob()
+                && (mDynamicConstraints & CONSTRAINT_DEVICE_NOT_DOZING) == 0);
     }
 
     boolean canRunInBatterySaver() {
         return (getInternalFlags() & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0
-                || shouldTreatAsExpeditedJob();
+                || (shouldTreatAsExpeditedJob()
+                && (mDynamicConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) == 0);
     }
 
     boolean shouldIgnoreNetworkBlocking() {
@@ -1245,6 +1264,14 @@
     }
 
     /**
+     * Add additional constraints to prevent this job from running when doze or battery saver are
+     * active.
+     */
+    public void disallowRunInBatterySaverAndDoze() {
+        addDynamicConstraints(DYNAMIC_EXPEDITED_DEFERRAL_CONSTRAINTS);
+    }
+
+    /**
      * Indicates that this job cannot run without the specified constraints. This is evaluated
      * separately from the job's explicitly requested constraints and MUST be satisfied before
      * the job can run if the app doesn't have quota.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 2faa836..b70e68b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -995,12 +995,18 @@
         if (standbyBucket == NEVER_INDEX) {
             return 0;
         }
+
         List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+        final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
         if (sessions == null || sessions.size() == 0) {
+            // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can
+            // essentially run until they reach the maximum limit.
+            if (stats.windowSizeMs == mAllowedTimePerPeriodMs) {
+                return mMaxExecutionTimeMs;
+            }
             return mAllowedTimePerPeriodMs;
         }
 
-        final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
         final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
         final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
         final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs;
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index b18a22b..1d6f20d 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -47,6 +47,7 @@
     static_libs: [
         "exoplayer2-extractor",
         "mediatranscoding_aidl_interface-java",
+        "modules-annotation-minsdk",
         "modules-utils-build",
     ],
     jarjar_rules: "jarjar_rules.txt",
@@ -108,7 +109,7 @@
 filegroup {
     name: "mediaparser-srcs",
     srcs: [
-        "java/android/media/MediaParser.java"
+        "java/android/media/MediaParser.java",
     ],
     path: "java",
 }
diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt
index eb71fdd..91489dc 100644
--- a/apex/media/framework/jarjar_rules.txt
+++ b/apex/media/framework/jarjar_rules.txt
@@ -1,2 +1,2 @@
-rule com.android.modules.utils.** android.media.internal.utils.@1
+rule com.android.modules.** android.media.internal.@1
 rule com.google.android.exoplayer2.** android.media.internal.exo.@1
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index 685cf0d..906071f 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -39,10 +39,12 @@
  for handling newer video codec format and media features.
 
  <p>
- Android 12 introduces seamless media transcoding feature. By default, Android assumes apps can
- support playback of all media formats. Apps that would like to request that media be transcoded
- into a more compatible format should declare their media capabilities in a media_capabilities
- .xml resource file and add it as a property tag in the AndroidManifest.xml file. Here is a example:
+ Android 12 introduces Compatible media transcoding feature.  See
+ <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
+ Compatible media transcoding</a>. By default, Android assumes apps can support playback of all
+ media formats. Apps that would like to request that media be transcoded into a more compatible
+ format should declare their media capabilities in a media_capabilities.xml resource file and add it
+ as a property tag in the AndroidManifest.xml file. Here is a example:
  <pre>
  {@code
  <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index 9ec25fe..f39bcfb 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -27,12 +27,14 @@
 import android.content.Context;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.media.MediaBrowserService;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.modules.annotation.MinSdk;
 import com.android.modules.utils.build.SdkLevel;
 
 import java.util.Collections;
@@ -45,6 +47,7 @@
  * Provides support for interacting with {@link android.media.MediaSession2 MediaSession2s}
  * that applications have published to express their ongoing media playback state.
  */
+@MinSdk(Build.VERSION_CODES.S)
 @SystemService(Context.MEDIA_COMMUNICATION_SERVICE)
 public class MediaCommunicationManager {
     private static final String TAG = "MediaCommunicationManager";
diff --git a/apex/media/framework/java/android/media/MediaSession2.java b/apex/media/framework/java/android/media/MediaSession2.java
index 6397ba3..7697359 100644
--- a/apex/media/framework/java/android/media/MediaSession2.java
+++ b/apex/media/framework/java/android/media/MediaSession2.java
@@ -32,6 +32,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.media.session.MediaSessionManager;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.os.BadParcelableException;
 import android.os.Bundle;
@@ -43,6 +44,8 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -86,6 +89,7 @@
     private final String mSessionId;
     private final PendingIntent mSessionActivity;
     private final Session2Token mSessionToken;
+    private final MediaSessionManager mMediaSessionManager;
     private final MediaCommunicationManager mCommunicationManager;
     private final Handler mResultHandler;
 
@@ -114,7 +118,13 @@
         mSessionStub = new Session2Link(this);
         mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
                 mSessionStub, tokenExtras);
-        mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
+        if (SdkLevel.isAtLeastS()) {
+            mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
+            mMediaSessionManager = null;
+        } else {
+            mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
+            mCommunicationManager = null;
+        }
         // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
         mResultHandler = new Handler(context.getMainLooper());
         mClosed = false;
@@ -315,6 +325,14 @@
         return mCallback;
     }
 
+    boolean isTrustedForMediaControl(RemoteUserInfo remoteUserInfo) {
+        if (SdkLevel.isAtLeastS()) {
+            return mCommunicationManager.isTrustedForMediaControl(remoteUserInfo);
+        } else {
+            return mMediaSessionManager.isTrustedForMediaControl(remoteUserInfo);
+        }
+    }
+
     void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) {
         synchronized (mLock) {
             if (mForegroundServiceEventCallback == callback) {
@@ -350,7 +368,7 @@
 
         final ControllerInfo controllerInfo = new ControllerInfo(
                 remoteUserInfo,
-                mCommunicationManager.isTrustedForMediaControl(remoteUserInfo),
+                isTrustedForMediaControl(remoteUserInfo),
                 controller,
                 connectionHints);
         mCallbackExecutor.execute(() -> {
@@ -606,9 +624,15 @@
             // Notify framework about the newly create session after the constructor is finished.
             // Otherwise, framework may access the session before the initialization is finished.
             try {
-                MediaCommunicationManager manager =
-                        mContext.getSystemService(MediaCommunicationManager.class);
-                manager.notifySession2Created(session2.getToken());
+                if (SdkLevel.isAtLeastS()) {
+                    MediaCommunicationManager manager =
+                            mContext.getSystemService(MediaCommunicationManager.class);
+                    manager.notifySession2Created(session2.getToken());
+                } else {
+                    MediaSessionManager manager =
+                            mContext.getSystemService(MediaSessionManager.class);
+                    manager.notifySession2Created(session2.getToken());
+                }
             } catch (Exception e) {
                 session2.close();
                 throw e;
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index f85e30d..9c044b5 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -66,6 +66,7 @@
     private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
             "set-phone-acct-suggestion-component";
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
+    private static final String COMMAND_SET_CALL_DIAGNOSTIC_SERVICE = "set-call-diagnostic-service";
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
     private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
@@ -112,6 +113,7 @@
                 + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
                 + " <LABEL> <ADDRESS>\n"
                 + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-call-diagnostic-service <PACKAGE>\n"
                 + "usage: telecom set-default-dialer <PACKAGE>\n"
                 + "usage: telecom get-default-dialer\n"
                 + "usage: telecom get-system-dialer\n"
@@ -131,6 +133,7 @@
                 + "telecom set-phone-account-disabled: Disables the given phone account, if it"
                         + " has already been registered with telecom.\n"
                 + "\n"
+                + "telecom set-call-diagnostic-service: overrides call diagnostic service.\n"
                 + "telecom set-default-dialer: Sets the override default dialer to the given"
                         + " component; this will override whatever the dialer role is set to.\n"
                 + "\n"
@@ -206,6 +209,9 @@
             case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
                 runSetTestPhoneAcctSuggestionComponent();
                 break;
+            case COMMAND_SET_CALL_DIAGNOSTIC_SERVICE:
+                runSetCallDiagnosticService();
+                break;
             case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
                 runRegisterSimPhoneAccount();
                 break;
@@ -323,6 +329,13 @@
         mTelecomService.addOrRemoveTestCallCompanionApp(packageName, isAddedBool);
     }
 
+    private void runSetCallDiagnosticService() throws RemoteException {
+        String packageName = nextArg();
+        if ("default".equals(packageName)) packageName = null;
+        mTelecomService.setTestCallDiagnosticService(packageName);
+        System.out.println("Success - " + packageName + " set as call diagnostic service.");
+    }
+
     private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
         final String componentName = nextArg();
         mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
diff --git a/core/api/current.txt b/core/api/current.txt
index 8733632..a06f994 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6810,14 +6810,18 @@
   public final class WallpaperColors implements android.os.Parcelable {
     ctor public WallpaperColors(android.os.Parcel);
     ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color);
+    ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
     method public int describeContents();
     method public static android.app.WallpaperColors fromBitmap(@NonNull android.graphics.Bitmap);
     method public static android.app.WallpaperColors fromDrawable(android.graphics.drawable.Drawable);
+    method public int getColorHints();
     method @NonNull public android.graphics.Color getPrimaryColor();
     method @Nullable public android.graphics.Color getSecondaryColor();
     method @Nullable public android.graphics.Color getTertiaryColor();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
+    field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
+    field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
   }
 
   public final class WallpaperInfo implements android.os.Parcelable {
@@ -11764,6 +11768,7 @@
     method public boolean isResourceOverlay();
     method public boolean isVirtualPreload();
     method public CharSequence loadDescription(android.content.pm.PackageManager);
+    field public static final int CATEGORY_ACCESSIBILITY = 8; // 0x8
     field public static final int CATEGORY_AUDIO = 1; // 0x1
     field public static final int CATEGORY_GAME = 0; // 0x0
     field public static final int CATEGORY_IMAGE = 3; // 0x3
@@ -12943,6 +12948,27 @@
 
 }
 
+package android.content.pm.verify.domain {
+
+  public final class DomainVerificationManager {
+    method @Nullable public android.content.pm.verify.domain.DomainVerificationUserState getDomainVerificationUserState(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+  }
+
+  public final class DomainVerificationUserState implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
+    method @NonNull public String getPackageName();
+    method @NonNull public android.os.UserHandle getUser();
+    method @NonNull public boolean isLinkHandlingAllowed();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserState> CREATOR;
+    field public static final int DOMAIN_STATE_NONE = 0; // 0x0
+    field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
+    field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
+  }
+
+}
+
 package android.content.res {
 
   public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
@@ -17531,6 +17557,9 @@
   public class BiometricManager {
     method @Deprecated @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate();
     method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public CharSequence getButtonLabel(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public CharSequence getPromptMessage(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public CharSequence getSettingName(int);
     field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
     field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb
     field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
@@ -18565,6 +18594,23 @@
 
 package android.hardware.display {
 
+  public final class DeviceProductInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConnectionToSinkType();
+    method public int getManufactureWeek();
+    method public int getManufactureYear();
+    method @NonNull public String getManufacturerPnpId();
+    method public int getModelYear();
+    method @Nullable public String getName();
+    method @NonNull public String getProductId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1
+    field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2
+    field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3
+    field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR;
+  }
+
   public final class DisplayManager {
     method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
     method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
@@ -20279,6 +20325,10 @@
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_BIT_WIDTH;
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_CHANNEL_MASK;
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.String> KEY_MIME;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PRESENTATION_ID;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.String> KEY_PRESENTATION_LANGUAGE;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PROGRAM_ID;
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_SAMPLE_RATE;
   }
 
@@ -20333,6 +20383,15 @@
     method public boolean hasAudioDescription();
     method public boolean hasDialogueEnhancement();
     method public boolean hasSpokenSubtitles();
+    field public static final int CONTENT_COMMENTARY = 5; // 0x5
+    field public static final int CONTENT_DIALOG = 4; // 0x4
+    field public static final int CONTENT_EMERGENCY = 6; // 0x6
+    field public static final int CONTENT_HEARING_IMPAIRED = 3; // 0x3
+    field public static final int CONTENT_MAIN = 0; // 0x0
+    field public static final int CONTENT_MUSIC_AND_EFFECTS = 1; // 0x1
+    field public static final int CONTENT_UNKNOWN = -1; // 0xffffffff
+    field public static final int CONTENT_VISUALLY_IMPAIRED = 2; // 0x2
+    field public static final int CONTENT_VOICEOVER = 7; // 0x7
     field public static final int MASTERED_FOR_3D = 3; // 0x3
     field public static final int MASTERED_FOR_HEADPHONE = 4; // 0x4
     field public static final int MASTERED_FOR_STEREO = 1; // 0x1
@@ -25866,6 +25925,7 @@
     method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms();
     method public int getTruncationLengthBits();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final String AUTH_AES_CMAC = "cmac(aes)";
     field public static final String AUTH_AES_XCBC = "xcbc(aes)";
     field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
     field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
@@ -26007,6 +26067,16 @@
     field public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; // 0x6
   }
 
+  public final class Proxy {
+    ctor public Proxy();
+    method @Deprecated public static String getDefaultHost();
+    method @Deprecated public static int getDefaultPort();
+    method @Deprecated public static String getHost(android.content.Context);
+    method @Deprecated public static int getPort(android.content.Context);
+    field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+    field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
+  }
+
   @Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     ctor @Deprecated public SSLCertificateSocketFactory(int);
     method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException;
@@ -26678,7 +26748,22 @@
 
   public class VcnManager {
     method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException;
+    method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback);
     method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException;
+    method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback);
+    field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1
+    field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0
+    field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2
+    field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2
+    field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1
+    field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0
+    field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3
+  }
+
+  public abstract static class VcnManager.VcnStatusCallback {
+    ctor public VcnManager.VcnStatusCallback();
+    method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
+    method public abstract void onVcnStatusChanged(int);
   }
 
 }
@@ -30228,6 +30313,7 @@
     field public static final String HARDWARE;
     field public static final String HOST;
     field public static final String ID;
+    field public static final boolean IS_DEBUGGABLE;
     field public static final String MANUFACTURER;
     field public static final String MODEL;
     field @NonNull public static final String ODM_SKU;
@@ -30386,19 +30472,10 @@
   public abstract class CombinedVibrationEffect implements android.os.Parcelable {
     method @NonNull public static android.os.CombinedVibrationEffect createSynced(@NonNull android.os.VibrationEffect);
     method public int describeContents();
-    method @NonNull public static android.os.CombinedVibrationEffect.SequentialCombination startSequential();
     method @NonNull public static android.os.CombinedVibrationEffect.SyncedCombination startSynced();
     field @NonNull public static final android.os.Parcelable.Creator<android.os.CombinedVibrationEffect> CREATOR;
   }
 
-  public static final class CombinedVibrationEffect.SequentialCombination {
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect);
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect, int);
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect);
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect, int);
-    method @NonNull public android.os.CombinedVibrationEffect combine();
-  }
-
   public static final class CombinedVibrationEffect.SyncedCombination {
     method @NonNull public android.os.CombinedVibrationEffect.SyncedCombination addVibrator(int, @NonNull android.os.VibrationEffect);
     method @NonNull public android.os.CombinedVibrationEffect combine();
@@ -31823,6 +31900,7 @@
     method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method @WorkerThread public long getCacheQuotaBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method @WorkerThread public long getCacheSizeBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) public android.app.PendingIntent getManageSpaceActivityIntent(@NonNull String, int);
     method public String getMountedObbPath(String);
     method @NonNull public android.os.storage.StorageVolume getPrimaryStorageVolume();
     method @NonNull public java.util.List<android.os.storage.StorageVolume> getRecentStorageVolumes();
@@ -38948,6 +39026,10 @@
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
     field @Deprecated public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE = "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE";
+    field public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE = "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE";
+    field public static final String EXTRA_DIAGNOSTIC_MESSAGE = "android.telecom.extra.DIAGNOSTIC_MESSAGE";
+    field public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID = "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID";
     field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
     field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
@@ -41312,7 +41394,6 @@
     method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
     method public int getDomain();
-    method public int getNrState();
     method @Nullable public String getRegisteredPlmn();
     method public int getTransportType();
     method public boolean isRegistered();
@@ -42199,7 +42280,6 @@
     field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
     field public static final int CALL_COMPOSER_STATUS_OFF = 0; // 0x0
     field public static final int CALL_COMPOSER_STATUS_ON = 1; // 0x1
-    field public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2; // 0x2
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -45848,7 +45928,7 @@
     method public void clear();
     method public android.util.SparseArray<E> clone();
     method public boolean contains(int);
-    method public boolean contentEquals(@Nullable android.util.SparseArray<E>);
+    method public boolean contentEquals(@Nullable android.util.SparseArray<?>);
     method public int contentHashCode();
     method public void delete(int);
     method public E get(int);
@@ -46244,6 +46324,7 @@
     method public long getAppVsyncOffsetNanos();
     method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
     method @Nullable public android.view.DisplayCutout getCutout();
+    method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo();
     method public int getDisplayId();
     method public int getFlags();
     method public android.view.Display.HdrCapabilities getHdrCapabilities();
@@ -49720,9 +49801,12 @@
   }
 
   public interface WindowManager extends android.view.ViewManager {
+    method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
     method @Deprecated public android.view.Display getDefaultDisplay();
     method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
+    method public default boolean isCrossWindowBlurEnabled();
+    method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void removeViewImmediate(android.view.View);
   }
 
@@ -49747,12 +49831,14 @@
     method public final int copyFrom(android.view.WindowManager.LayoutParams);
     method public String debug(String);
     method public int describeContents();
+    method public int getBlurBehindRadius();
     method public int getColorMode();
     method public int getFitInsetsSides();
     method public int getFitInsetsTypes();
     method public final CharSequence getTitle();
     method public boolean isFitInsetsIgnoringVisibility();
     method public static boolean mayUseInputMethod(int);
+    method public void setBlurBehindRadius(@IntRange(from=0) int);
     method public void setColorMode(int);
     method public void setFitInsetsIgnoringVisibility(boolean);
     method public void setFitInsetsSides(int);
@@ -49863,7 +49949,6 @@
     field @Deprecated public static final int TYPE_TOAST = 2005; // 0x7d5
     field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
     field public float alpha;
-    field public int blurBehindRadius;
     field public float buttonBrightness;
     field public float dimAmount;
     field public int flags;
@@ -50028,7 +50113,7 @@
     method public boolean canOpenPopup();
     method public int describeContents();
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String);
-    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String);
+    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(@NonNull String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
@@ -50930,6 +51015,7 @@
     method public void onDisplayHashError(int);
     method public void onDisplayHashResult(@NonNull android.view.displayhash.DisplayHash);
     field public static final int DISPLAY_HASH_ERROR_INVALID_BOUNDS = -2; // 0xfffffffe
+    field public static final int DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM = -5; // 0xfffffffb
     field public static final int DISPLAY_HASH_ERROR_MISSING_WINDOW = -3; // 0xfffffffd
     field public static final int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4; // 0xfffffffc
     field public static final int DISPLAY_HASH_ERROR_UNKNOWN = -1; // 0xffffffff
@@ -51290,7 +51376,6 @@
     method public int describeContents();
     method public void dump(android.util.Printer, String);
     method public android.content.ComponentName getComponent();
-    method public int getConfigChanges();
     method public String getId();
     method public int getIsDefaultResourceId();
     method public String getPackageName();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 7ea7d61..d6786f8 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -44,6 +44,14 @@
 
 }
 
+package android.app.usage {
+
+  public class NetworkStatsManager {
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>);
+  }
+
+}
+
 package android.content {
 
   public abstract class Context {
@@ -167,10 +175,26 @@
     method public int getResourceId();
   }
 
+  public final class NetworkStateSnapshot implements android.os.Parcelable {
+    ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR;
+    field public final int legacyType;
+    field @NonNull public final android.net.LinkProperties linkProperties;
+    field @NonNull public final android.net.Network network;
+    field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
+    field @Nullable public final String subscriberId;
+  }
+
   public class NetworkWatchlistManager {
     method @Nullable public byte[] getWatchlistConfigHash();
   }
 
+  public final class Proxy {
+    method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
+  }
+
   public final class UnderlyingNetworkInfo implements android.os.Parcelable {
     ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>);
     method public int describeContents();
@@ -217,8 +241,8 @@
 package android.os.storage {
 
   public class StorageManager {
-    method public void notifyAppIoBlocked(@NonNull String, int, int, int);
-    method public void notifyAppIoResumed(@NonNull String, int, int, int);
+    method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
+    method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
     field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0; // 0x0
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c4b16ec..b4f3698 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -32,6 +32,7 @@
     field public static final String BATTERY_PREDICTION = "android.permission.BATTERY_PREDICTION";
     field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
     field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
+    field public static final String BIND_CALL_DIAGNOSTIC_SERVICE = "android.permission.BIND_CALL_DIAGNOSTIC_SERVICE";
     field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
     field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
     field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
@@ -153,6 +154,7 @@
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
+    field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
     field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
     field public static final String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
     field public static final String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
@@ -356,6 +358,7 @@
     field public static final int config_systemGallery = 17039399; // 0x1040027
     field public static final int config_systemShell = 17039402; // 0x104002a
     field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
+    field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
   }
 
   public static final class R.style {
@@ -422,6 +425,9 @@
     method @Nullable public static String opToPermission(@NonNull String);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
+    field public static final int HISTORY_FLAGS_ALL = 3; // 0x3
+    field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1
+    field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2
     field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
     field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
     field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
@@ -535,9 +541,14 @@
     method public long getAccessDuration(int, int, int);
     method public long getBackgroundAccessCount(int);
     method public long getBackgroundAccessDuration(int);
+    method @NonNull public java.util.List<android.app.AppOpsManager.AttributedOpEntry> getBackgroundDiscreteAccesses(int);
     method public long getBackgroundRejectCount(int);
+    method @NonNull public android.app.AppOpsManager.AttributedOpEntry getDiscreteAccessAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getDiscreteAccessCount();
+    method @NonNull public java.util.List<android.app.AppOpsManager.AttributedOpEntry> getDiscreteAccesses(int, int, int);
     method public long getForegroundAccessCount(int);
     method public long getForegroundAccessDuration(int);
+    method @NonNull public java.util.List<android.app.AppOpsManager.AttributedOpEntry> getForegroundDiscreteAccesses(int);
     method public long getForegroundRejectCount(int);
     method @NonNull public String getOpName();
     method public long getRejectCount(int, int, int);
@@ -564,6 +575,7 @@
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setHistoryFlags(int);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
@@ -647,7 +659,6 @@
     method public void setDontSendToRestrictedApps(boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(int, long);
     method public android.os.Bundle toBundle();
   }
 
@@ -858,13 +869,6 @@
     method public void onVrStateChanged(boolean);
   }
 
-  public final class WallpaperColors implements android.os.Parcelable {
-    ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
-    method public int getColorHints();
-    field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
-    field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
-  }
-
   public final class WallpaperInfo implements android.os.Parcelable {
     method public boolean supportsAmbientMode();
   }
@@ -962,6 +966,9 @@
 
 package android.app.assist {
 
+  public class ActivityId {
+  }
+
   public static class AssistStructure.ViewNode {
     ctor public AssistStructure.ViewNode();
   }
@@ -1892,11 +1899,18 @@
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
     field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+    field public static final String DEVICE_TYPE_DEFAULT = "Default";
+    field public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
+    field public static final String DEVICE_TYPE_WATCH = "Watch";
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
+    field public static final int METADATA_DEVICE_TYPE = 17; // 0x11
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
     field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
+    field public static final int METADATA_MAIN_BATTERY = 18; // 0x12
+    field public static final int METADATA_MAIN_CHARGING = 19; // 0x13
     field public static final int METADATA_MAIN_ICON = 5; // 0x5
+    field public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; // 0x14
     field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
     field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
     field public static final int METADATA_MODEL_NAME = 1; // 0x1
@@ -1904,12 +1918,15 @@
     field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
     field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
     field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
+    field public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; // 0x17
     field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
     field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
     field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
+    field public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; // 0x15
     field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
     field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
     field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
+    field public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; // 0x16
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -2557,9 +2574,7 @@
     field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
     field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
     field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
-    field public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
-    field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
-    field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version";
+    field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
     field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
     field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
     field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
@@ -2775,13 +2790,12 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationInfo> CREATOR;
   }
 
-  public interface DomainVerificationManager {
+  public final class DomainVerificationManager {
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.verify.domain.DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.List<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> getValidVerificationPackageNames();
     method public static boolean isStateModifiable(int);
     method public static boolean isStateVerified(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> queryValidVerificationPackageNames();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationLinkHandlingAllowed(@NonNull String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
     method @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public void setDomainVerificationStatus(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationUserSelection(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -2798,18 +2812,8 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationRequest> CREATOR;
   }
 
-  public final class DomainVerificationUserSelection implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
+  public final class DomainVerificationUserState implements android.os.Parcelable {
     method @NonNull public java.util.UUID getIdentifier();
-    method @NonNull public String getPackageName();
-    method @NonNull public android.os.UserHandle getUser();
-    method @NonNull public boolean isLinkHandlingAllowed();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserSelection> CREATOR;
-    field public static final int DOMAIN_STATE_NONE = 0; // 0x0
-    field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
-    field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
   }
 
 }
@@ -5088,9 +5092,10 @@
   }
 
   public static class AudioTrack.TunerConfiguration {
-    ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=1) int, @IntRange(from=1) int);
+    ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=0) int, @IntRange(from=1) int);
     method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getContentId();
     method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getSyncId();
+    field public static final int CONTENT_ID_NONE = 0; // 0x0
   }
 
   public class HwAudioSource {
@@ -7156,9 +7161,6 @@
     method public abstract void onRequestScores(android.net.NetworkKey[]);
   }
 
-  public class NetworkReleasedException extends java.lang.Exception {
-  }
-
   public class NetworkScoreManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
@@ -7242,47 +7244,6 @@
     method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
   }
 
-  public abstract class QosCallback {
-    ctor public QosCallback();
-    method public void onError(@NonNull android.net.QosCallbackException);
-    method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
-    method public void onQosSessionLost(@NonNull android.net.QosSession);
-  }
-
-  public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
-  }
-
-  public final class QosCallbackException extends java.lang.Exception {
-  }
-
-  public abstract class QosFilter {
-    method @NonNull public abstract android.net.Network getNetwork();
-    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
-  }
-
-  public final class QosSession implements android.os.Parcelable {
-    ctor public QosSession(int, int);
-    method public int describeContents();
-    method public int getSessionId();
-    method public int getSessionType();
-    method public long getUniqueId();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
-    field public static final int TYPE_EPS_BEARER = 1; // 0x1
-  }
-
-  public interface QosSessionAttributes {
-  }
-
-  public final class QosSocketInfo implements android.os.Parcelable {
-    ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
-    method public int describeContents();
-    method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
-    method @NonNull public android.net.Network getNetwork();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
-  }
-
   public class RssiCurve implements android.os.Parcelable {
     ctor public RssiCurve(int, int, byte[]);
     ctor public RssiCurve(int, int, byte[], int);
@@ -7314,12 +7275,6 @@
     field public final android.net.RssiCurve rssiCurve;
   }
 
-  public class SocketLocalAddressChangedException extends java.lang.Exception {
-  }
-
-  public class SocketNotBoundException extends java.lang.Exception {
-  }
-
   public class TrafficStats {
     method public static void setThreadStatsTagApp();
     method public static void setThreadStatsTagBackup();
@@ -7549,6 +7504,19 @@
 
 }
 
+package android.net.util {
+
+  public final class SocketUtils {
+    method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
+    method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
+    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
+  }
+
+}
+
 package android.net.vcn {
 
   public class VcnManager {
@@ -8247,10 +8215,11 @@
     field public static final int EVENT_MMS = 2; // 0x2
     field public static final int EVENT_SMS = 1; // 0x1
     field public static final int EVENT_UNSPECIFIED = 0; // 0x0
-    field public static final int REASON_ACTIVITY_RECOGNITION = 102; // 0x66
+    field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
     field public static final int REASON_GEOFENCING = 100; // 0x64
     field public static final int REASON_OTHER = 1; // 0x1
     field public static final int REASON_PUSH_MESSAGING = 101; // 0x65
+    field public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66
     field public static final int REASON_UNKNOWN = 0; // 0x0
     field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
     field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
@@ -8866,6 +8835,8 @@
     field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
     field public static final String NAMESPACE_SCHEDULER = "scheduler";
+    field public static final String NAMESPACE_STATSD_JAVA = "statsd_java";
+    field public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot";
     field public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
     field public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
     field @Deprecated public static final String NAMESPACE_STORAGE = "storage";
@@ -10068,10 +10039,10 @@
 
   public abstract class ExternalStorageService extends android.app.Service {
     ctor public ExternalStorageService();
+    method public void onAnrDelayStarted(@NonNull String, int, int, int);
     method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onEndSession(@NonNull String) throws java.io.IOException;
     method public void onFreeCache(@NonNull java.util.UUID, long) throws java.io.IOException;
-    method public long onGetAnrDelayMillis(@NonNull String, int);
     method public abstract void onStartSession(@NonNull String, int, @NonNull android.os.ParcelFileDescriptor, @NonNull java.io.File, @NonNull java.io.File) throws java.io.IOException;
     method public abstract void onVolumeStateChanged(@NonNull android.os.storage.StorageVolume) throws java.io.IOException;
     field public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 2; // 0x2
@@ -10269,7 +10240,7 @@
   public abstract class HotwordDetectionService extends android.app.Service {
     ctor public HotwordDetectionService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
-    method public void onDetectFromDspSource(int, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
+    method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
     field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
   }
 
@@ -10381,6 +10352,16 @@
     ctor @Deprecated public Call.Listener();
   }
 
+  public abstract class CallDiagnosticService extends android.app.Service {
+    ctor public CallDiagnosticService();
+    method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public abstract void onBluetoothCallQualityReportReceived(@NonNull android.telecom.BluetoothCallQualityReport);
+    method public abstract void onCallAudioStateChanged(@NonNull android.telecom.CallAudioState);
+    method @NonNull public abstract android.telecom.DiagnosticCall onInitializeDiagnosticCall(@NonNull android.telecom.Call.Details);
+    method public abstract void onRemoveDiagnosticCall(@NonNull android.telecom.DiagnosticCall);
+    field public static final String SERVICE_INTERFACE = "android.telecom.CallDiagnosticService";
+  }
+
   public static class CallScreeningService.CallResponse.Builder {
     method @NonNull @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallViaAudioProcessing(boolean);
   }
@@ -10413,6 +10394,9 @@
     method public void setTelecomCallId(@NonNull String);
     field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
     field public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 262144; // 0x40000
+    field public static final String EVENT_DEVICE_TO_DEVICE_MESSAGE = "android.telecom.event.DEVICE_TO_DEVICE_MESSAGE";
+    field public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE = "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_TYPE";
+    field public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE = "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE";
     field public static final String EXTRA_DISABLE_ADD_CALL = "android.telecom.extra.DISABLE_ADD_CALL";
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1; // 0x1
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
@@ -10438,6 +10422,34 @@
     method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
   }
 
+  public abstract class DiagnosticCall {
+    ctor public DiagnosticCall();
+    method public final void clearDiagnosticMessage(int);
+    method public final void displayDiagnosticMessage(int, @NonNull CharSequence);
+    method @NonNull public android.telecom.Call.Details getCallDetails();
+    method public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details);
+    method @Nullable public abstract CharSequence onCallDisconnected(int, int);
+    method @Nullable public abstract CharSequence onCallDisconnected(@NonNull android.telephony.ims.ImsReasonInfo);
+    method public abstract void onCallQualityReceived(@NonNull android.telephony.CallQuality);
+    method public abstract void onReceiveDeviceToDeviceMessage(int, int);
+    method public final void sendDeviceToDeviceMessage(int, int);
+    field public static final int AUDIO_CODEC_AMR_NB = 3; // 0x3
+    field public static final int AUDIO_CODEC_AMR_WB = 2; // 0x2
+    field public static final int AUDIO_CODEC_EVS = 1; // 0x1
+    field public static final int BATTERY_STATE_CHARGING = 3; // 0x3
+    field public static final int BATTERY_STATE_GOOD = 2; // 0x2
+    field public static final int BATTERY_STATE_LOW = 1; // 0x1
+    field public static final int COVERAGE_GOOD = 2; // 0x2
+    field public static final int COVERAGE_POOR = 1; // 0x1
+    field public static final int MESSAGE_CALL_AUDIO_CODEC = 2; // 0x2
+    field public static final int MESSAGE_CALL_NETWORK_TYPE = 1; // 0x1
+    field public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; // 0x3
+    field public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; // 0x4
+    field public static final int NETWORK_TYPE_IWLAN = 2; // 0x2
+    field public static final int NETWORK_TYPE_LTE = 1; // 0x1
+    field public static final int NETWORK_TYPE_NR = 3; // 0x3
+  }
+
   public abstract class InCallService extends android.app.Service {
     method @Deprecated public android.telecom.Phone getPhone();
     method @Deprecated public void onPhoneCreated(android.telecom.Phone);
@@ -13039,7 +13051,7 @@
     method @NonNull public String getServiceId();
     method @NonNull public String getServiceVersion();
     method @NonNull public String getStatus();
-    method @Nullable public String getTimestamp();
+    method @Nullable public java.time.Instant getTime();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
     field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
@@ -13066,7 +13078,7 @@
     method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
     method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
     method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
-    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTimestamp(@NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTime(@NonNull java.time.Instant);
   }
 
   public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
@@ -13122,7 +13134,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
-    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
     field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
     field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
@@ -13598,7 +13610,7 @@
     ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
     method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
     method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
-    method public void subscribeForCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
+    method public void subscribeForCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
     field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
     field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
     field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
@@ -14004,6 +14016,7 @@
 
   public final class ContentCaptureContext implements android.os.Parcelable {
     method @Nullable public android.content.ComponentName getActivityComponent();
+    method @Nullable public android.app.assist.ActivityId getActivityId();
     method public int getDisplayId();
     method public int getFlags();
     method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
@@ -14066,9 +14079,13 @@
 
   public final class UiTranslationManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(@NonNull android.app.assist.ActivityId);
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(@NonNull android.app.assist.ActivityId);
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(@NonNull android.app.assist.ActivityId);
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId);
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1c54e84..e4757e6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -224,6 +224,9 @@
     field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
     field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
     field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
+    field public static final int HISTORY_FLAGS_ALL = 3; // 0x3
+    field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1
+    field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2
     field public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
     field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
     field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
@@ -238,6 +241,7 @@
 
   public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
     ctor public AppOpsManager.HistoricalOps(long, long);
+    method public void addDiscreteAccess(int, int, @NonNull String, @Nullable String, int, int, long, long);
     method public void increaseAccessCount(int, int, @NonNull String, @Nullable String, int, int, long);
     method public void increaseAccessDuration(int, int, @NonNull String, @Nullable String, int, int, long);
     method public void increaseRejectCount(int, int, @NonNull String, @Nullable String, int, int, long);
@@ -399,6 +403,8 @@
     method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);
     method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
     method public void forceUpdateUserSetupComplete();
+    method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
+    method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
     method public long getLastBugReportRequestTime();
     method public long getLastNetworkLogRetrievalTime();
     method public long getLastSecurityLogRetrievalTime();
@@ -544,6 +550,15 @@
 
 }
 
+package android.app.assist {
+
+  public class ActivityId {
+    method public int getTaskId();
+    method @Nullable public android.os.IBinder getToken();
+  }
+
+}
+
 package android.app.blob {
 
   public class BlobStoreManager {
@@ -707,6 +722,10 @@
     field public int privateFlags;
   }
 
+  public class CrossProfileApps {
+    method public boolean canConfigureInteractAcrossProfiles(@NonNull String);
+  }
+
   public class LauncherApps {
     ctor public LauncherApps(android.content.Context);
   }
@@ -1017,17 +1036,19 @@
 package android.hardware.devicestate {
 
   public final class DeviceStateManager {
-    method public void addDeviceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
     method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
     method @NonNull public int[] getSupportedStates();
-    method public void removeDeviceStateListener(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
+    method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
     method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+    method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
     field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
     field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
   }
 
-  public static interface DeviceStateManager.DeviceStateListener {
-    method public void onDeviceStateChanged(int);
+  public static interface DeviceStateManager.DeviceStateCallback {
+    method public default void onBaseStateChanged(int);
+    method public void onStateChanged(int);
+    method public default void onSupportedStatesChanged(@NonNull int[]);
   }
 
   public final class DeviceStateRequest {
@@ -1468,6 +1489,7 @@
 
   public abstract class CombinedVibrationEffect implements android.os.Parcelable {
     method public abstract long getDuration();
+    method @NonNull public static android.os.CombinedVibrationEffect.SequentialCombination startSequential();
   }
 
   public static final class CombinedVibrationEffect.Mono extends android.os.CombinedVibrationEffect {
@@ -1485,6 +1507,14 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.os.CombinedVibrationEffect.Sequential> CREATOR;
   }
 
+  public static final class CombinedVibrationEffect.SequentialCombination {
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect, int);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect, int);
+    method @NonNull public android.os.CombinedVibrationEffect combine();
+  }
+
   public static final class CombinedVibrationEffect.Stereo extends android.os.CombinedVibrationEffect {
     method public long getDuration();
     method @NonNull public android.util.SparseArray<android.os.VibrationEffect> getEffects();
@@ -2570,6 +2600,9 @@
 package android.view.contentcapture {
 
   public final class ContentCaptureManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void resetTemporaryService(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void setDefaultServiceEnabled(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void setTemporaryService(int, @NonNull String, int);
     field public static final String DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY = "idle_flush_frequency";
     field public static final String DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL = "logging_level";
     field public static final String DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE = "log_history_size";
@@ -2660,10 +2693,6 @@
     method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
   }
 
-  public final class InputMethodInfo implements android.os.Parcelable {
-    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
-  }
-
   public final class InputMethodManager {
     method public int getDisplayId();
     method public boolean hasActiveInputConnection(@Nullable android.view.View);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a73fe71..f5f0b42 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -803,6 +803,7 @@
     @UnsupportedAppUsage
     private IBinder mToken;
     private IBinder mAssistToken;
+    private IBinder mShareableActivityToken;
     @UnsupportedAppUsage
     private int mIdent;
     @UnsupportedAppUsage
@@ -1210,7 +1211,7 @@
                     if (window != null) {
                         cm.updateWindowAttributes(window.getAttributes());
                     }
-                    cm.onActivityCreated(mToken, getComponentName());
+                    cm.onActivityCreated(mToken, mShareableActivityToken, getComponentName());
                     break;
                 case CONTENT_CAPTURE_RESUME:
                     cm.onActivityResumed();
@@ -7118,6 +7119,9 @@
                 case "--contentcapture":
                     dumpContentCaptureManager(prefix, writer);
                     return;
+                case "--translation":
+                    dumpUiTranslation(prefix, writer);
+                    return;
             }
         }
         writer.print(prefix); writer.print("Local Activity ");
@@ -7158,6 +7162,7 @@
 
         dumpAutofillManager(prefix, writer);
         dumpContentCaptureManager(prefix, writer);
+        dumpUiTranslation(prefix, writer);
 
         ResourcesManager.getInstance().dump(prefix, writer);
     }
@@ -7182,6 +7187,14 @@
         }
     }
 
+    void dumpUiTranslation(String prefix, PrintWriter writer) {
+        if (mUiTranslationController != null) {
+            mUiTranslationController.dump(prefix, writer);
+        } else {
+            writer.print(prefix); writer.println("No UiTranslationController");
+        }
+    }
+
     /**
      * Bit indicating that this activity is "immersive" and should not be
      * interrupted by notifications if possible.
@@ -7838,7 +7851,8 @@
             CharSequence title, Activity parent, String id,
             NonConfigurationInstances lastNonConfigurationInstances,
             Configuration config, String referrer, IVoiceInteractor voiceInteractor,
-            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
+            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
+            IBinder shareableActivityToken) {
         attachBaseContext(context);
 
         mFragments.attachHost(null /*parent*/);
@@ -7860,6 +7874,7 @@
         mInstrumentation = instr;
         mToken = token;
         mAssistToken = assistToken;
+        mShareableActivityToken = shareableActivityToken;
         mIdent = ident;
         mApplication = application;
         mIntent = intent;
@@ -7918,6 +7933,11 @@
     }
 
     /** @hide */
+    public final IBinder getShareableActivityToken() {
+        return mParent != null ? mParent.getShareableActivityToken() : mShareableActivityToken;
+    }
+
+    /** @hide */
     @VisibleForTesting
     public final ActivityThread getActivityThread() {
         return mMainThread;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 73cc13c8..a1dce77 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -320,6 +320,10 @@
     private static final String KEY_OVERRIDE_TASK_TRANSITION =
             "android:activity.overrideTaskTransition";
 
+    /** See {@link #setRemoveWithTaskOrganizer(boolean)}. */
+    private static final String KEY_REMOVE_WITH_TASK_ORGANIZER =
+            "android.activity.removeWithTaskOrganizer";
+
     /**
      * @see #setLaunchCookie
      * @hide
@@ -405,6 +409,7 @@
     private IRemoteTransition mRemoteTransition;
     private boolean mOverrideTaskTransition;
     private int mSplashScreenThemeResId;
+    private boolean mRemoveWithTaskOrganizer;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -1155,6 +1160,7 @@
                 KEY_REMOTE_TRANSITION));
         mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
         mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME);
+        mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
     }
 
     /**
@@ -1624,6 +1630,22 @@
     }
 
     /**
+     * Sets whether to remove the task when TaskOrganizer, which is managing it, is destroyed.
+     * @hide
+     */
+    public void setRemoveWithTaskOrganizer(boolean remove) {
+        mRemoveWithTaskOrganizer = remove;
+    }
+
+    /**
+     * @return whether to remove the task when TaskOrganizer, which is managing it, is destroyed.
+     * @hide
+     */
+    public boolean getRemoveWithTaskOranizer() {
+        return mRemoveWithTaskOrganizer;
+    }
+
+    /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
      * defined in <var>otherOptions</var> replace those in the base options.
@@ -1857,6 +1879,9 @@
         if (mSplashScreenThemeResId != 0) {
             b.putInt(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResId);
         }
+        if (mRemoveWithTaskOrganizer) {
+            b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer);
+        }
         return b;
     }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 47d2e7c..e7751b8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -176,6 +176,8 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.autofill.AutofillId;
+import android.view.contentcapture.IContentCaptureManager;
+import android.view.contentcapture.IContentCaptureOptionsCallback;
 import android.view.translation.TranslationSpec;
 import android.webkit.WebView;
 import android.window.SplashScreen;
@@ -512,11 +514,16 @@
 
     boolean mHasImeComponent = false;
 
+    private IContentCaptureOptionsCallback.Stub mContentCaptureOptionsCallback = null;
+
     /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
     public static final class ActivityClientRecord {
         @UnsupportedAppUsage
         public IBinder token;
         public IBinder assistToken;
+        // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
+        // used without security checks
+        public IBinder shareableActivityToken;
         int ident;
         @UnsupportedAppUsage
         Intent intent;
@@ -604,9 +611,11 @@
                 PersistableBundle persistentState, List<ResultInfo> pendingResults,
                 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
-                IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
+                IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
+                IBinder shareableActivityToken) {
             this.token = token;
             this.assistToken = assistToken;
+            this.shareableActivityToken = shareableActivityToken;
             this.ident = ident;
             this.intent = intent;
             this.referrer = referrer;
@@ -1934,6 +1943,7 @@
         public static final int PURGE_RESOURCES = 161;
         public static final int ATTACH_STARTUP_AGENTS = 162;
         public static final int UPDATE_UI_TRANSLATION_STATE = 163;
+        public static final int SET_CONTENT_CAPTURE_OPTIONS_CALLBACK = 164;
 
         public static final int INSTRUMENT_WITHOUT_RESTART = 170;
         public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
@@ -1983,6 +1993,8 @@
                     case PURGE_RESOURCES: return "PURGE_RESOURCES";
                     case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
                     case UPDATE_UI_TRANSLATION_STATE: return "UPDATE_UI_TRANSLATION_STATE";
+                    case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
+                        return "SET_CONTENT_CAPTURE_OPTIONS_CALLBACK";
                     case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
                     case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
                         return "FINISH_INSTRUMENTATION_WITHOUT_RESTART";
@@ -2175,6 +2187,9 @@
                             (TranslationSpec) args.arg3, (TranslationSpec) args.arg4,
                             (List<AutofillId>) args.arg5);
                     break;
+                case SET_CONTENT_CAPTURE_OPTIONS_CALLBACK:
+                    handleSetContentCaptureOptionsCallback((String) msg.obj);
+                    break;
                 case INSTRUMENT_WITHOUT_RESTART:
                     handleInstrumentWithoutRestart((AppBindData) msg.obj);
                     break;
@@ -3157,11 +3172,13 @@
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Activity startActivityNow(Activity parent, String id,
-        Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
-        Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken) {
+            Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
+            Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken,
+            IBinder shareableActivityToken) {
         ActivityClientRecord r = new ActivityClientRecord();
             r.token = token;
             r.assistToken = assistToken;
+            r.shareableActivityToken = shareableActivityToken;
             r.ident = 0;
             r.intent = intent;
             r.state = state;
@@ -3504,7 +3521,7 @@
                         r.ident, app, r.intent, r.activityInfo, title, r.parent,
                         r.embeddedID, r.lastNonConfigurationInstances, config,
                         r.referrer, r.voiceInteractor, window, r.configCallback,
-                        r.assistToken);
+                        r.assistToken, r.shareableActivityToken);
 
                 if (customIntent != null) {
                     activity.mIntent = customIntent;
@@ -6788,6 +6805,7 @@
 
             // Propagate Content Capture options
             app.setContentCaptureOptions(data.contentCaptureOptions);
+            sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);
 
             mInitialApplication = app;
 
@@ -6849,6 +6867,36 @@
         }
     }
 
+    private void handleSetContentCaptureOptionsCallback(String packageName) {
+        if (mContentCaptureOptionsCallback != null) {
+            return;
+        }
+
+        IBinder b = ServiceManager.getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
+        if (b == null) {
+            return;
+        }
+
+        IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
+        mContentCaptureOptionsCallback = new IContentCaptureOptionsCallback.Stub() {
+            @Override
+            public void setContentCaptureOptions(ContentCaptureOptions options)
+                    throws RemoteException {
+                if (mInitialApplication != null) {
+                    mInitialApplication.setContentCaptureOptions(options);
+                }
+            }
+        };
+        try {
+            service.registerContentCaptureOptionsCallback(packageName,
+                    mContentCaptureOptionsCallback);
+        } catch (RemoteException e)  {
+            Slog.w(TAG, "registerContentCaptureOptionsCallback() failed: "
+                    + packageName, e);
+            mContentCaptureOptionsCallback = null;
+        }
+    }
+
     private void handleInstrumentWithoutRestart(AppBindData data) {
         try {
             data.compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 160844a..dd1bc7c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static java.lang.Long.max;
+
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
@@ -3385,6 +3387,13 @@
         @DataClass.ParcelWith(LongSparseArrayParceling.class)
         private final @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
 
+        private AttributedOpEntry(@NonNull AttributedOpEntry other) {
+            mOp = other.mOp;
+            mRunning = other.mRunning;
+            mAccessEvents = other.mAccessEvents == null ? null : other.mAccessEvents.clone();
+            mRejectEvents = other.mRejectEvents == null ? null : other.mRejectEvents.clone();
+        }
+
         /**
          * Returns all keys for which we have events.
          *
@@ -3749,6 +3758,15 @@
             return lastEvent.getProxy();
         }
 
+        @NonNull
+        String getOpName() {
+            return AppOpsManager.opToPublicName(mOp);
+        }
+
+        int getOp() {
+            return mOp;
+        }
+
         private static class LongSparseArrayParceling implements
                 Parcelling<LongSparseArray<NoteOpEvent>> {
             @Override
@@ -4571,6 +4589,50 @@
     }
 
     /**
+     * Flag for querying app op history: get only aggregate information and no
+     * discrete accesses.
+     *
+     * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final int HISTORY_FLAG_AGGREGATE = 1 << 0;
+
+    /**
+     * Flag for querying app op history: get only discrete information and no
+     * aggregate accesses.
+     *
+     * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final int HISTORY_FLAG_DISCRETE = 1 << 1;
+
+    /**
+     * Flag for querying app op history: get all types of historical accesses.
+     *
+     * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final int HISTORY_FLAGS_ALL = HISTORY_FLAG_AGGREGATE
+            | HISTORY_FLAG_DISCRETE;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "HISTORY_FLAG_" }, value = {
+            HISTORY_FLAG_AGGREGATE,
+            HISTORY_FLAG_DISCRETE
+    })
+    public @interface OpHistoryFlags {}
+
+    /**
      * Specifies what parameters to filter historical appop requests for
      *
      * @hide
@@ -4625,6 +4687,7 @@
         private final @Nullable String mPackageName;
         private final @Nullable String mAttributionTag;
         private final @Nullable List<String> mOpNames;
+        private final @OpHistoryFlags int mHistoryFlags;
         private final @HistoricalOpsRequestFilter int mFilter;
         private final long mBeginTimeMillis;
         private final long mEndTimeMillis;
@@ -4632,12 +4695,13 @@
 
         private HistoricalOpsRequest(int uid, @Nullable String packageName,
                 @Nullable String attributionTag, @Nullable List<String> opNames,
-                @HistoricalOpsRequestFilter int filter, long beginTimeMillis,
-                long endTimeMillis, @OpFlags int flags) {
+                @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
+                long beginTimeMillis, long endTimeMillis, @OpFlags int flags) {
             mUid = uid;
             mPackageName = packageName;
             mAttributionTag = attributionTag;
             mOpNames = opNames;
+            mHistoryFlags = historyFlags;
             mFilter = filter;
             mBeginTimeMillis = beginTimeMillis;
             mEndTimeMillis = endTimeMillis;
@@ -4655,6 +4719,7 @@
             private @Nullable String mPackageName;
             private @Nullable String mAttributionTag;
             private @Nullable List<String> mOpNames;
+            private @OpHistoryFlags int mHistoryFlags;
             private @HistoricalOpsRequestFilter int mFilter;
             private final long mBeginTimeMillis;
             private final long mEndTimeMillis;
@@ -4676,6 +4741,7 @@
                         "beginTimeMillis must be non negative and lesser than endTimeMillis");
                 mBeginTimeMillis = beginTimeMillis;
                 mEndTimeMillis = endTimeMillis;
+                mHistoryFlags = HISTORY_FLAG_AGGREGATE;
             }
 
             /**
@@ -4772,11 +4838,25 @@
             }
 
             /**
+             * Specifies what type of historical information to query.
+             *
+             * @param flags Flags for the historical types to fetch which are any
+             * combination of {@link #HISTORY_FLAG_AGGREGATE}, {@link #HISTORY_FLAG_DISCRETE},
+             * {@link #HISTORY_FLAGS_ALL}. The default is {@link #HISTORY_FLAG_AGGREGATE}.
+             * @return This builder.
+             */
+            public @NonNull Builder setHistoryFlags(@OpHistoryFlags int flags) {
+                Preconditions.checkFlagsArgument(flags, HISTORY_FLAGS_ALL);
+                mHistoryFlags = flags;
+                return this;
+            }
+
+            /**
              * @return a new {@link HistoricalOpsRequest}.
              */
             public @NonNull HistoricalOpsRequest build() {
                 return new HistoricalOpsRequest(mUid, mPackageName, mAttributionTag, mOpNames,
-                        mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
+                        mHistoryFlags, mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
             }
         }
     }
@@ -4943,7 +5023,8 @@
          * @hide
          */
         public void filter(int uid, @Nullable String packageName, @Nullable String attributionTag,
-                @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
+                @Nullable String[] opNames, @OpHistoryFlags int historyFilter,
+                @HistoricalOpsRequestFilter int filter,
                 long beginTimeMillis, long endTimeMillis) {
             final long durationMillis = getDurationMillis();
             mBeginTimeMillis = Math.max(mBeginTimeMillis, beginTimeMillis);
@@ -4956,7 +5037,8 @@
                 if ((filter & FILTER_BY_UID) != 0 && uid != uidOp.getUid()) {
                     mHistoricalUidOps.removeAt(i);
                 } else {
-                    uidOp.filter(packageName, attributionTag, opNames, filter, scaleFactor);
+                    uidOp.filter(packageName, attributionTag, opNames, filter, historyFilter,
+                            scaleFactor, mBeginTimeMillis, mEndTimeMillis);
                     if (uidOp.getPackageCount() == 0) {
                         mHistoricalUidOps.removeAt(i);
                     }
@@ -5013,6 +5095,16 @@
 
         /** @hide */
         @TestApi
+        public void addDiscreteAccess(int opCode, int uid, @NonNull String packageName,
+                @Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
+                long discreteAccessTime, long discreteAccessDuration) {
+            getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
+                    uidState, opFlag, discreteAccessTime, discreteAccessDuration);
+        };
+
+
+        /** @hide */
+        @TestApi
         public void offsetBeginAndEndTime(long offsetMillis) {
             mBeginTimeMillis += offsetMillis;
             mEndTimeMillis += offsetMillis;
@@ -5288,7 +5380,8 @@
 
         private void filter(@Nullable String packageName, @Nullable String attributionTag,
                 @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
-                double fractionToRemove) {
+                @OpHistoryFlags int historyFilter, double fractionToRemove, long beginTimeMillis,
+                long endTimeMillis) {
             final int packageCount = getPackageCount();
             for (int i = packageCount - 1; i >= 0; i--) {
                 final HistoricalPackageOps packageOps = getPackageOpsAt(i);
@@ -5296,7 +5389,8 @@
                         packageOps.getPackageName())) {
                     mHistoricalPackageOps.removeAt(i);
                 } else {
-                    packageOps.filter(attributionTag, opNames, filter, fractionToRemove);
+                    packageOps.filter(attributionTag, opNames, filter, historyFilter,
+                            fractionToRemove, beginTimeMillis, endTimeMillis);
                     if (packageOps.getAttributedOpsCount() == 0) {
                         mHistoricalPackageOps.removeAt(i);
                     }
@@ -5336,6 +5430,13 @@
                     opCode, attributionTag, uidState, flags, increment);
         }
 
+        private void addDiscreteAccess(int opCode, @NonNull String packageName,
+                @Nullable String attributionTag, @UidState int uidState,
+                @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration) {
+            getOrCreateHistoricalPackageOps(packageName).addDiscreteAccess(opCode, attributionTag,
+                    uidState, flag, discreteAccessTime, discreteAccessDuration);
+        };
+
         /**
          * @return The UID for which the data is related.
          */
@@ -5540,7 +5641,8 @@
         }
 
         private void filter(@Nullable String attributionTag, @Nullable String[] opNames,
-                @HistoricalOpsRequestFilter int filter, double fractionToRemove) {
+                @HistoricalOpsRequestFilter int filter, @OpHistoryFlags int historyFilter,
+                double fractionToRemove, long beginTimeMillis, long endTimeMillis) {
             final int attributionCount = getAttributedOpsCount();
             for (int i = attributionCount - 1; i >= 0; i--) {
                 final AttributedHistoricalOps attributionOps = getAttributedOpsAt(i);
@@ -5548,7 +5650,8 @@
                         attributionOps.getTag())) {
                     mAttributedHistoricalOps.removeAt(i);
                 } else {
-                    attributionOps.filter(opNames, filter, fractionToRemove);
+                    attributionOps.filter(opNames, filter, historyFilter, fractionToRemove,
+                            beginTimeMillis, endTimeMillis);
                     if (attributionOps.getOpCount() == 0) {
                         mAttributedHistoricalOps.removeAt(i);
                     }
@@ -5593,6 +5696,13 @@
                     opCode, uidState, flags, increment);
         }
 
+        private void addDiscreteAccess(int opCode, @Nullable String attributionTag,
+                @UidState int uidState, @OpFlags int flag, long discreteAccessTime,
+                long discreteAccessDuration) {
+            getOrCreateAttributedHistoricalOps(attributionTag).addDiscreteAccess(opCode, uidState,
+                    flag, discreteAccessTime, discreteAccessDuration);
+        }
+
         /**
          * Gets the package name which the data represents.
          *
@@ -5870,7 +5980,8 @@
         }
 
         private void filter(@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
-                double scaleFactor) {
+                @OpHistoryFlags int historyFilter, double scaleFactor, long beginTimeMillis,
+                long endTimeMillis) {
             final int opCount = getOpCount();
             for (int i = opCount - 1; i >= 0; i--) {
                 final HistoricalOp op = mHistoricalOps.valueAt(i);
@@ -5878,7 +5989,7 @@
                         op.getOpName())) {
                     mHistoricalOps.removeAt(i);
                 } else {
-                    op.filter(scaleFactor);
+                    op.filter(historyFilter, scaleFactor, beginTimeMillis, endTimeMillis);
                 }
             }
         }
@@ -5909,6 +6020,12 @@
             getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, flags, increment);
         }
 
+        private void addDiscreteAccess(int opCode, @UidState int uidState, @OpFlags int flag,
+                long discreteAccessTime, long discreteAccessDuration) {
+            getOrCreateHistoricalOp(opCode).addDiscreteAccess(uidState,flag, discreteAccessTime,
+                    discreteAccessDuration);
+        }
+
         /**
          * Gets number historical app ops.
          *
@@ -5970,8 +6087,6 @@
             return op;
         }
 
-
-
         // Code below generated by codegen v1.0.14.
         //
         // DO NOT MODIFY!
@@ -6121,6 +6236,9 @@
         private @Nullable LongSparseLongArray mRejectCount;
         private @Nullable LongSparseLongArray mAccessDuration;
 
+        /** Discrete Ops for this Op */
+        private @Nullable List<AttributedOpEntry> mDiscreteAccesses;
+
         /** @hide */
         public HistoricalOp(int op) {
             mOp = op;
@@ -6137,6 +6255,12 @@
             if (other.mAccessDuration != null) {
                 mAccessDuration = other.mAccessDuration.clone();
             }
+            final int historicalOpCount = other.getDiscreteAccessCount();
+            for (int i = 0; i < historicalOpCount; i++) {
+                final AttributedOpEntry origOp = other.getDiscreteAccessAt(i);
+                final AttributedOpEntry cloneOp = new AttributedOpEntry(origOp);
+                getOrCreateDiscreteAccesses().add(cloneOp);
+            }
         }
 
         private HistoricalOp(@NonNull Parcel parcel) {
@@ -6144,22 +6268,45 @@
             mAccessCount = readLongSparseLongArrayFromParcel(parcel);
             mRejectCount = readLongSparseLongArrayFromParcel(parcel);
             mAccessDuration = readLongSparseLongArrayFromParcel(parcel);
+            mDiscreteAccesses = readDiscreteAccessArrayFromParcel(parcel);
         }
 
-        private void filter(double scaleFactor) {
-            scale(mAccessCount, scaleFactor);
-            scale(mRejectCount, scaleFactor);
-            scale(mAccessDuration, scaleFactor);
+        private void filter(@OpHistoryFlags int historyFlag, double scaleFactor,
+                long beginTimeMillis, long endTimeMillis) {
+            if ((historyFlag & HISTORY_FLAG_AGGREGATE) == 0) {
+                mAccessCount = null;
+                mRejectCount = null;
+                mAccessDuration = null;
+            } else {
+                scale(mAccessCount, scaleFactor);
+                scale(mRejectCount, scaleFactor);
+                scale(mAccessDuration, scaleFactor);
+            }
+            if ((historyFlag & HISTORY_FLAG_DISCRETE) == 0) {
+                mDiscreteAccesses = null;
+                return;
+            }
+            final int discreteOpCount = getDiscreteAccessCount();
+            for (int i = discreteOpCount - 1; i >= 0; i--) {
+                final AttributedOpEntry op = mDiscreteAccesses.get(i);
+                long opBeginTime = op.getLastAccessTime(OP_FLAGS_ALL);
+                long opEndTime = opBeginTime + op.getLastDuration(OP_FLAGS_ALL);
+                opEndTime = max(opBeginTime, opEndTime);
+                if (opEndTime < beginTimeMillis || opBeginTime > endTimeMillis) {
+                    mDiscreteAccesses.remove(i);
+                }
+            }
         }
 
         private boolean isEmpty() {
             return !hasData(mAccessCount)
                     && !hasData(mRejectCount)
-                    && !hasData(mAccessDuration);
+                    && !hasData(mAccessDuration)
+                    && (mDiscreteAccesses == null);
         }
 
         private boolean hasData(@NonNull LongSparseLongArray array) {
-            return (array != null && array.size() > 0);
+            return array != null && array.size() > 0;
         }
 
         private @Nullable HistoricalOp splice(double fractionToRemove) {
@@ -6191,6 +6338,32 @@
             merge(this::getOrCreateAccessCount, other.mAccessCount);
             merge(this::getOrCreateRejectCount, other.mRejectCount);
             merge(this::getOrCreateAccessDuration, other.mAccessDuration);
+
+            if (other.mDiscreteAccesses == null) {
+                return;
+            }
+            if (mDiscreteAccesses == null) {
+                mDiscreteAccesses = new ArrayList(other.mDiscreteAccesses);
+                return;
+            }
+            List<AttributedOpEntry> historicalDiscreteAccesses = new ArrayList<>();
+            final int otherHistoricalOpCount = other.getDiscreteAccessCount();
+            final int historicalOpCount = getDiscreteAccessCount();
+            int i = 0;
+            int j = 0;
+            while (i < otherHistoricalOpCount || j < historicalOpCount) {
+                if (i == otherHistoricalOpCount) {
+                    historicalDiscreteAccesses.add(mDiscreteAccesses.get(j++));
+                } else if (j == historicalOpCount) {
+                    historicalDiscreteAccesses.add(other.mDiscreteAccesses.get(i++));
+                } else if (mDiscreteAccesses.get(j).getLastAccessTime(OP_FLAGS_ALL)
+                        < other.mDiscreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL)) {
+                    historicalDiscreteAccesses.add(mDiscreteAccesses.get(j++));
+                } else {
+                    historicalDiscreteAccesses.add(other.mDiscreteAccesses.get(i++));
+                }
+            }
+            mDiscreteAccesses = historicalDiscreteAccesses;
         }
 
         private void increaseAccessCount(@UidState int uidState, @OpFlags int flags,
@@ -6218,6 +6391,23 @@
             }
         }
 
+        private void addDiscreteAccess(@UidState int uidState, @OpFlags int flag,
+                long discreteAccessTime, long discreteAccessDuration) {
+            List<AttributedOpEntry> discreteAccesses = getOrCreateDiscreteAccesses();
+            LongSparseArray<NoteOpEvent> accessEvents = new LongSparseArray<>();
+            long key = makeKey(uidState, flag);
+            NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null);
+            accessEvents.append(key, note);
+            AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null);
+            for (int i = discreteAccesses.size() - 1; i >= 0; i--) {
+                if (discreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) {
+                    discreteAccesses.add(i + 1, access);
+                    return;
+                }
+            }
+            discreteAccesses.add(0, access);
+        }
+
         /**
          * Gets the op name.
          *
@@ -6233,6 +6423,33 @@
         }
 
         /**
+         * Gets number of discrete historical app ops.
+         *
+         * @return The number historical app ops.
+         * @see #getOpAt(int)
+         */
+        public @IntRange(from = 0) int getDiscreteAccessCount() {
+            if (mDiscreteAccesses == null) {
+                return 0;
+            }
+            return mDiscreteAccesses.size();
+        }
+
+        /**
+         * Gets the historical op at a given index.
+         *
+         * @param index The index to lookup.
+         * @return The op at the given index.
+         * @see #getOpCount()
+         */
+        public @NonNull AttributedOpEntry getDiscreteAccessAt(@IntRange(from = 0) int index) {
+            if (mDiscreteAccesses == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mDiscreteAccesses.get(index);
+        }
+
+        /**
          * Gets the number times the op was accessed (performed) in the foreground.
          *
          * @param flags The flags which are any combination of
@@ -6251,6 +6468,25 @@
         }
 
         /**
+         * Gets the discrete events the op was accessed (performed) in the foreground.
+         *
+         * @param flags The flags which are any combination of
+         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+         * for any flag.
+         * @return The list of discrete ops accessed in the foreground.
+         *
+         * @see #getBackgroundDiscreteAccesses(int)
+         * @see #getDiscreteAccesses(int, int, int)
+         */
+        @NonNull
+        public List<AttributedOpEntry> getForegroundDiscreteAccesses(@OpFlags int flags) {
+            return listForFlagsInStates(mDiscreteAccesses, MAX_PRIORITY_UID_STATE,
+                    resolveFirstUnrestrictedUidState(mOp), flags);
+        }
+
+        /**
          * Gets the number times the op was accessed (performed) in the background.
          *
          * @param flags The flags which are any combination of
@@ -6269,6 +6505,25 @@
         }
 
         /**
+         * Gets the discrete events the op was accessed (performed) in the background.
+         *
+         * @param flags The flags which are any combination of
+         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+         * for any flag.
+         * @return The list of discrete ops accessed in the background.
+         *
+         * @see #getForegroundDiscreteAccesses(int)
+         * @see #getDiscreteAccesses(int, int, int)
+         */
+        @NonNull
+        public List<AttributedOpEntry> getBackgroundDiscreteAccesses(@OpFlags int flags) {
+            return listForFlagsInStates(mDiscreteAccesses, resolveLastRestrictedUidState(mOp),
+                    MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
          * Gets the number times the op was accessed (performed) for a
          * range of uid states.
          *
@@ -6294,6 +6549,26 @@
         }
 
         /**
+         * Gets the discrete events the op was accessed (performed) for a
+         * range of uid states.
+         *
+         * @param flags The flags which are any combination of
+         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+         * for any flag.
+         * @return The discrete the op was accessed in the background.
+         *
+         * @see #getBackgroundDiscreteAccesses(int)
+         * @see #getForegroundDiscreteAccesses(int)
+         */
+        @NonNull
+        public List<AttributedOpEntry> getDiscreteAccesses(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            return listForFlagsInStates(mDiscreteAccesses, fromUidState, toUidState, flags);
+        }
+
+        /**
          * Gets the number times the op was rejected in the foreground.
          *
          * @param flags The flags which are any combination of
@@ -6427,6 +6702,7 @@
             writeLongSparseLongArrayToParcel(mAccessCount, parcel);
             writeLongSparseLongArrayToParcel(mRejectCount, parcel);
             writeLongSparseLongArrayToParcel(mAccessDuration, parcel);
+            writeDiscreteAccessArrayToParcel(mDiscreteAccesses, parcel);
         }
 
         @Override
@@ -6447,7 +6723,11 @@
             if (!equalsLongSparseLongArray(mRejectCount, other.mRejectCount)) {
                 return false;
             }
-            return equalsLongSparseLongArray(mAccessDuration, other.mAccessDuration);
+            if (!equalsLongSparseLongArray(mAccessDuration, other.mAccessDuration)) {
+                return false;
+            }
+            return mDiscreteAccesses == null ? (other.mDiscreteAccesses == null ? true
+                    : false) : mDiscreteAccesses.equals(other.mDiscreteAccesses);
         }
 
         @Override
@@ -6456,6 +6736,7 @@
             result = 31 * result + Objects.hashCode(mAccessCount);
             result = 31 * result + Objects.hashCode(mRejectCount);
             result = 31 * result + Objects.hashCode(mAccessDuration);
+            result = 31 * result + Objects.hashCode(mDiscreteAccesses);
             return result;
         }
 
@@ -6484,6 +6765,13 @@
             return mAccessDuration;
         }
 
+        private @NonNull List<AttributedOpEntry> getOrCreateDiscreteAccesses() {
+            if (mDiscreteAccesses == null) {
+                mDiscreteAccesses = new ArrayList<>();
+            }
+            return mDiscreteAccesses;
+        }
+
         /**
          * Multiplies the entries in the array with the passed in scale factor and
          * rounds the result at up 0.5 boundary.
@@ -6574,6 +6862,32 @@
     }
 
     /**
+     * Returns list of events filtered by UidState and UID flags.
+     *
+     * @param accesses The events list.
+     * @param beginUidState The beginning UID state (inclusive).
+     * @param endUidState The end UID state (inclusive).
+     * @param flags The UID flags.
+     * @return filtered list of events.
+     */
+    private static List<AttributedOpEntry> listForFlagsInStates(List<AttributedOpEntry> accesses,
+            @UidState int beginUidState, @UidState int endUidState, @OpFlags int flags) {
+        List<AttributedOpEntry> result = new ArrayList<>();
+        if (accesses == null) {
+            return result;
+        }
+        int nAccesses = accesses.size();
+        for (int i = 0; i < nAccesses; i++) {
+            AttributedOpEntry entry = accesses.get(i);
+            if (entry.getLastAccessTime(beginUidState, endUidState, flags) == -1) {
+                continue;
+            }
+            result.add(entry);
+        }
+        return result;
+    }
+
+    /**
      * Callback for notification of changes to operation state.
      */
     public interface OnOpChangedListener {
@@ -6796,8 +7110,9 @@
         Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOps(request.mUid, request.mPackageName, request.mAttributionTag,
-                    request.mOpNames, request.mFilter, request.mBeginTimeMillis,
-                    request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
+                    request.mOpNames, request.mHistoryFlags, request.mFilter,
+                    request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
+                    new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
                 try {
@@ -6835,9 +7150,9 @@
         Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
-                    request.mAttributionTag, request.mOpNames, request.mFilter,
-                    request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
-                    new RemoteCallback((result) -> {
+                    request.mAttributionTag, request.mOpNames, request.mHistoryFlags,
+                    request.mFilter, request.mBeginTimeMillis, request.mEndTimeMillis,
+                    request.mFlags, new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
                 try {
@@ -9072,6 +9387,32 @@
         return array;
     }
 
+    private static void writeDiscreteAccessArrayToParcel(
+            @Nullable List<AttributedOpEntry> array, @NonNull Parcel parcel) {
+        if (array != null) {
+            final int size = array.size();
+            parcel.writeInt(size);
+            for (int i = 0; i < size; i++) {
+                array.get(i).writeToParcel(parcel, 0);
+            }
+        } else {
+            parcel.writeInt(-1);
+        }
+    }
+
+    private static @Nullable List<AttributedOpEntry> readDiscreteAccessArrayFromParcel(
+            @NonNull Parcel parcel) {
+        final int size = parcel.readInt();
+        if (size < 0) {
+            return null;
+        }
+        final List<AttributedOpEntry> array = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            array.add(new AttributedOpEntry(parcel));
+        }
+        return array;
+    }
+
     /**
      * Collects the keys from an array to the result creating the result if needed.
      *
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 2e06e9b..477e96b 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -144,23 +144,6 @@
      * Set a duration for which the system should temporary place an application on the
      * power allowlist when this broadcast is being delivered to it, specify the temp allowlist
      * type.
-     * @param type one of {@link TempAllowListType}
-     * @param duration the duration in milliseconds; 0 means to not place on allowlist.
-     * @deprecated use {@link #setTemporaryAppAllowlist(long, int, int,  String)} instead.
-     */
-    @Deprecated
-    @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
-            android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
-            android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
-    public void setTemporaryAppWhitelistDuration(@TempAllowListType int type, long duration) {
-        setTemporaryAppAllowlist(duration, type,
-                PowerWhitelistManager.REASON_UNKNOWN, null);
-    }
-
-    /**
-     * Set a duration for which the system should temporary place an application on the
-     * power allowlist when this broadcast is being delivered to it, specify the temp allowlist
-     * type.
      * @param duration the duration in milliseconds; 0 means to not place on allowlist.
      * @param type one of {@link TempAllowListType}
      * @param reasonCode one of {@link ReasonCode}, use
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 8d1076e..b2184fe 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1247,7 +1247,8 @@
                 info, title, parent, id,
                 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
                 new Configuration(), null /* referrer */, null /* voiceInteractor */,
-                null /* window */, null /* activityConfigCallback */, null /*assistToken*/);
+                null /* window */, null /* activityConfigCallback */, null /*assistToken*/,
+                null /*shareableActivityToken*/);
         return activity;
     }
 
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 74e6125..6b5f19a 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -158,7 +158,7 @@
                 r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);
             }
             r.activity = mActivityThread.startActivityNow(
-                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r);
+                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r, r);
             if (r.activity == null) {
                 return;
             }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8167622..bc24e97 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -24,6 +24,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.AttrRes;
 import android.annotation.ColorInt;
 import android.annotation.ColorRes;
 import android.annotation.DimenRes;
@@ -98,6 +99,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ContrastColorUtil;
 
@@ -3649,11 +3651,6 @@
         private int mCachedContrastColorIsFor = COLOR_INVALID;
 
         /**
-         * A neutral color color that can be used for icons.
-         */
-        private int mNeutralColor = COLOR_INVALID;
-
-        /**
          * Caches an instance of StandardTemplateParams. Note that this may have been used before,
          * so make sure to call {@link StandardTemplateParams#reset()} before using it.
          */
@@ -3666,6 +3663,7 @@
         private boolean mRebuildStyledRemoteViews;
 
         private boolean mTintActionButtons;
+        private boolean mTintWithThemeAccent;
         private boolean mInNightMode;
 
         /**
@@ -3701,6 +3699,7 @@
             mContext = context;
             Resources res = mContext.getResources();
             mTintActionButtons = res.getBoolean(R.bool.config_tintNotificationActionButtons);
+            mTintWithThemeAccent = res.getBoolean(R.bool.config_tintNotificationsWithTheme);
 
             if (res.getBoolean(R.bool.config_enableNightMode)) {
                 Configuration currentConfig = res.getConfiguration();
@@ -4891,12 +4890,10 @@
         }
 
         private void bindPhishingAlertIcon(RemoteViews contentView, StandardTemplateParams p) {
-            // TODO(b/180334837): Get buy-in on this color, or make sure to give this the
-            //  accent color, while still accommodating the colorized state.
             contentView.setDrawableTint(
                     R.id.phishing_alert,
                     false /* targetBackground */,
-                    getPrimaryTextColor(p),
+                    getErrorColor(p),
                     PorterDuff.Mode.SRC_ATOP);
         }
 
@@ -4943,7 +4940,7 @@
             contentView.setDrawableTint(
                     R.id.alerted_icon,
                     false /* targetBackground */,
-                    getNeutralColor(p),
+                    getHeaderIconColor(p),
                     PorterDuff.Mode.SRC_ATOP);
         }
 
@@ -5057,10 +5054,9 @@
             return text;
         }
 
-        private void setTextViewColorPrimary(RemoteViews contentView, int id,
+        private void setTextViewColorPrimary(RemoteViews contentView, @IdRes int id,
                 StandardTemplateParams p) {
-            ensureColors(p);
-            contentView.setTextColor(id, mPrimaryTextColor);
+            contentView.setTextColor(id, getPrimaryTextColor(p));
         }
 
         private boolean hasForegroundColor() {
@@ -5068,53 +5064,34 @@
         }
 
         /**
-         * Return the primary text color using the existing template params
-         * @hide
-         */
-        @VisibleForTesting
-        public int getPrimaryTextColor() {
-            return getPrimaryTextColor(mParams);
-        }
-
-        /**
          * @param p the template params to inflate this with
          * @return the primary text color
          * @hide
          */
         @VisibleForTesting
-        public int getPrimaryTextColor(StandardTemplateParams p) {
+        public @ColorInt int getPrimaryTextColor(StandardTemplateParams p) {
             ensureColors(p);
             return mPrimaryTextColor;
         }
 
         /**
-         * Return the secondary text color using the existing template params
-         * @hide
-         */
-        @VisibleForTesting
-        public int getSecondaryTextColor() {
-            return getSecondaryTextColor(mParams);
-        }
-
-        /**
          * @param p the template params to inflate this with
          * @return the secondary text color
          * @hide
          */
         @VisibleForTesting
-        public int getSecondaryTextColor(StandardTemplateParams p) {
+        public @ColorInt int getSecondaryTextColor(StandardTemplateParams p) {
             ensureColors(p);
             return mSecondaryTextColor;
         }
 
-        private void setTextViewColorSecondary(RemoteViews contentView, int id,
+        private void setTextViewColorSecondary(RemoteViews contentView, @IdRes int id,
                 StandardTemplateParams p) {
-            ensureColors(p);
-            contentView.setTextColor(id, mSecondaryTextColor);
+            contentView.setTextColor(id, getSecondaryTextColor(p));
         }
 
         private void ensureColors(StandardTemplateParams p) {
-            int backgroundColor = getBackgroundColor(p);
+            int backgroundColor = getUnresolvedBackgroundColor(p);
             if (mPrimaryTextColor == COLOR_INVALID
                     || mSecondaryTextColor == COLOR_INVALID
                     || mTextColorsAreForBackground != backgroundColor) {
@@ -5217,7 +5194,7 @@
                         R.id.progress, ColorStateList.valueOf(mContext.getColor(
                                 R.color.notification_progress_background_color)));
                 if (getRawColor(p) != COLOR_DEFAULT) {
-                    int color = isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p);
+                    int color = getAccentColor(p);
                     ColorStateList colorStateList = ColorStateList.valueOf(color);
                     contentView.setProgressTintList(R.id.progress, colorStateList);
                     contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
@@ -5326,11 +5303,18 @@
         }
 
         private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) {
-            int color = isColorized(p) ? getPrimaryTextColor(p) : getSecondaryTextColor(p);
-            contentView.setDrawableTint(R.id.expand_button, false, color,
-                    PorterDuff.Mode.SRC_ATOP);
-            contentView.setInt(R.id.expand_button, "setOriginalNotificationColor",
-                    color);
+            // set default colors
+            int textColor = getPrimaryTextColor(p);
+            int pillColor = getProtectionColor(p);
+            contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor);
+            contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
+            // Use different highlighted colors except when low-priority mode prevents that
+            if (!p.forceDefaultColor) {
+                textColor = getBackgroundColor(p);
+                pillColor = getAccentColor(p);
+            }
+            contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
+            contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
         }
 
         private void bindHeaderChronometerAndTime(RemoteViews contentView,
@@ -5461,11 +5445,7 @@
             }
             contentView.setViewVisibility(R.id.app_name_text, View.VISIBLE);
             contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
-            if (isColorized(p)) {
-                setTextViewColorPrimary(contentView, R.id.app_name_text, p);
-            } else {
-                contentView.setTextColor(R.id.app_name_text, getSecondaryTextColor(p));
-            }
+            contentView.setTextColor(R.id.app_name_text, getSecondaryTextColor(p));
             return true;
         }
 
@@ -5555,6 +5535,10 @@
 
             resetStandardTemplateWithActions(big);
             bindSnoozeAction(big, p);
+            // color the snooze and bubble actions with the theme color
+            ColorStateList actionColor = ColorStateList.valueOf(getStandardActionColor(p));
+            big.setColorStateList(R.id.snooze_button, "setImageTintList", actionColor);
+            big.setColorStateList(R.id.bubble_button, "setImageTintList", actionColor);
 
             boolean validRemoteInput = false;
 
@@ -5604,8 +5588,7 @@
                         showSpinner ? View.VISIBLE : View.GONE);
                 big.setProgressIndeterminateTintList(
                         R.id.notification_material_reply_progress,
-                        ColorStateList.valueOf(
-                                isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p)));
+                        ColorStateList.valueOf(getAccentColor(p)));
 
                 if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText())
                         && p.maxRemoteInputHistory > 1) {
@@ -6021,14 +6004,14 @@
                 // change the background bgColor
                 CharSequence title = action.title;
                 ColorStateList[] outResultColor = new ColorStateList[1];
-                int background = resolveBackgroundColor(p);
+                int background = getBackgroundColor(p);
                 if (isLegacy()) {
                     title = ContrastColorUtil.clearColorSpans(title);
                 } else {
                     title = ensureColorSpanContrast(title, background, outResultColor);
                 }
                 button.setTextViewText(R.id.action0, processTextSpans(title));
-                int textColor = getPrimaryTextColor(p);
+                final int textColor;
                 boolean hasColorOverride = outResultColor[0] != null;
                 if (hasColorOverride) {
                     // There's a span spanning the full text, let's take it and use it as the
@@ -6036,9 +6019,11 @@
                     background = outResultColor[0].getDefaultColor();
                     textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
                             background, mInNightMode);
-                } else if (getRawColor(p) != COLOR_DEFAULT && !isColorized(p)
-                        && mTintActionButtons && !mInNightMode) {
-                    textColor = resolveContrastColor(p);
+                } else if (mTintActionButtons && !mInNightMode
+                        && getRawColor(p) != COLOR_DEFAULT && !isColorized(p)) {
+                    textColor = getAccentColor(p);
+                } else {
+                    textColor = getPrimaryTextColor(p);
                 }
                 button.setTextColor(R.id.action0, textColor);
                 // We only want about 20% alpha for the ripple
@@ -6056,11 +6041,7 @@
             } else {
                 button.setTextViewText(R.id.action0, processTextSpans(
                         processLegacyText(action.title)));
-                if (isColorized(p)) {
-                    setTextViewColorPrimary(button, R.id.action0, p);
-                } else if (getRawColor(p) != COLOR_DEFAULT && mTintActionButtons) {
-                    button.setTextColor(R.id.action0, resolveContrastColor(p));
-                }
+                button.setTextColor(R.id.action0, getStandardActionColor(p));
             }
             // CallStyle notifications add action buttons which don't actually exist in mActions,
             //  so we have to omit the index in that case.
@@ -6170,9 +6151,9 @@
         private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
                 StandardTemplateParams p) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
-            int color = isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p);
+            int color = getSmallIconColor(p);
             contentView.setInt(R.id.icon, "setBackgroundColor",
-                    resolveBackgroundColor(p));
+                    getBackgroundColor(p));
             contentView.setInt(R.id.icon, "setOriginalIconColor",
                     colorable ? color : COLOR_INVALID);
         }
@@ -6187,7 +6168,7 @@
             if (largeIcon != null && isLegacy()
                     && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                 // resolve color will fall back to the default when legacy
-                int color = resolveContrastColor(p);
+                int color = getContrastColor(p);
                 contentView.setInt(R.id.icon, "setOriginalIconColor", color);
             }
         }
@@ -6198,14 +6179,94 @@
             }
         }
 
-        int resolveContrastColor(StandardTemplateParams p) {
+        /**
+         * Gets the standard action button color
+         */
+        private @ColorInt int getStandardActionColor(Notification.StandardTemplateParams p) {
+            return mTintActionButtons || isColorized(p) ? getAccentColor(p) : getNeutralColor(p);
+        }
+
+        /**
+         * Gets a neutral color that can be used for icons or similar that should not stand out.
+         */
+        private @ColorInt int getHeaderIconColor(StandardTemplateParams p) {
+            return isColorized(p) ? getSecondaryTextColor(p) : getNeutralColor(p);
+        }
+
+        /**
+         * Gets the foreground color of the small icon.  If the notification is colorized, this
+         * is the primary text color, otherwise it's the contrast-adjusted app-provided color.
+         */
+        private @ColorInt int getSmallIconColor(StandardTemplateParams p) {
+            return isColorized(p) ? getPrimaryTextColor(p) : getContrastColor(p);
+        }
+
+        /**
+         * Gets the accent color for colored UI elements.  If we're tinting with the theme
+         * accent, this is the theme accent color, otherwise this would be identical to
+         * {@link #getSmallIconColor(StandardTemplateParams)}.
+         */
+        private @ColorInt int getAccentColor(StandardTemplateParams p) {
+            if (isColorized(p)) {
+                return getPrimaryTextColor(p);
+            }
+            if (mTintWithThemeAccent) {
+                int color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
+                if (color != COLOR_INVALID) {
+                    return color;
+                }
+            }
+            return getContrastColor(p);
+        }
+
+        /**
+         * Gets the "surface protection" color from the theme, or a variant of the normal background
+         * color when colorized, or when not using theme color tints.
+         */
+        private @ColorInt int getProtectionColor(StandardTemplateParams p) {
+            if (mTintWithThemeAccent && !isColorized(p)) {
+                int color = obtainThemeColor(R.attr.colorBackgroundFloating, COLOR_INVALID);
+                if (color != COLOR_INVALID) {
+                    return color;
+                }
+            }
+            // TODO(b/181048615): What color should we use for the expander pill when colorized
+            return ColorUtils.blendARGB(getPrimaryTextColor(p), getBackgroundColor(p), 0.8f);
+        }
+
+        /**
+         * Gets the theme's error color, or the primary text color for colorized notifications.
+         */
+        private @ColorInt int getErrorColor(StandardTemplateParams p) {
+            if (!isColorized(p)) {
+                int color = obtainThemeColor(R.attr.colorError, COLOR_INVALID);
+                if (color != COLOR_INVALID) {
+                    return color;
+                }
+            }
+            return getPrimaryTextColor(p);
+        }
+
+        /**
+         * Gets the theme's background color
+         */
+        private @ColorInt int getDefaultBackgroundColor() {
+            return obtainThemeColor(R.attr.colorBackground,
+                    mInNightMode ? Color.BLACK : Color.WHITE);
+        }
+
+        /**
+         * Gets the contrast-adjusted version of the color provided by the app.
+         */
+        private @ColorInt int getContrastColor(StandardTemplateParams p) {
             int rawColor = getRawColor(p);
             if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
                 return mCachedContrastColor;
             }
 
             int color;
-            int background = obtainBackgroundColor();
+            // TODO: Maybe use getBackgroundColor(p) instead -- but doing so could break the cache
+            int background = getDefaultBackgroundColor();
             if (rawColor == COLOR_DEFAULT) {
                 ensureColors(p);
                 color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode);
@@ -6224,28 +6285,29 @@
         /**
          * Return the raw color of this Notification, which doesn't necessarily satisfy contrast.
          *
-         * @see #resolveContrastColor(StandardTemplateParams) for the contrasted color
+         * @see #getContrastColor(StandardTemplateParams) for the contrasted color
          * @param p the template params to inflate this with
          */
-        private int getRawColor(StandardTemplateParams p) {
+        private @ColorInt int getRawColor(StandardTemplateParams p) {
             if (p.forceDefaultColor) {
                 return COLOR_DEFAULT;
             }
             return mN.color;
         }
 
-        int resolveNeutralColor() {
-            if (mNeutralColor != COLOR_INVALID) {
-                return mNeutralColor;
-            }
-            int background = obtainBackgroundColor();
-            mNeutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
+        /**
+         * Gets a neutral palette color; this is a contrast-satisfied version of the default color.
+         * @param p the template params to inflate this with
+         */
+        private @ColorInt int getNeutralColor(StandardTemplateParams p) {
+            int background = getBackgroundColor(p);
+            int neutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
                     mInNightMode);
-            if (Color.alpha(mNeutralColor) < 255) {
+            if (Color.alpha(neutralColor) < 255) {
                 // alpha doesn't go well for color filters, so let's blend it manually
-                mNeutralColor = ContrastColorUtil.compositeColors(mNeutralColor, background);
+                neutralColor = ContrastColorUtil.compositeColors(neutralColor, background);
             }
-            return mNeutralColor;
+            return neutralColor;
         }
 
         /**
@@ -6389,8 +6451,11 @@
             return mN;
         }
 
-        private @ColorInt int obtainBackgroundColor() {
-            int defaultColor = mInNightMode ? Color.BLACK : Color.WHITE;
+        /**
+         * Returns the color for the given Theme.DeviceDefault.DayNight attribute, or
+         * defValue if that could not be completed
+         */
+        private @ColorInt int obtainThemeColor(@AttrRes int attrRes, @ColorInt int defaultColor) {
             Resources.Theme theme = mContext.getTheme();
             if (theme == null) {
                 // Running unit tests with mocked context
@@ -6398,7 +6463,7 @@
             }
             theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
                     .getTheme();
-            TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.colorBackground});
+            TypedArray ta = theme.obtainStyledAttributes(new int[]{attrRes});
             if (ta == null) {
                 return defaultColor;
             }
@@ -6517,7 +6582,11 @@
             return R.layout.notification_material_action_tombstone;
         }
 
-        private int getBackgroundColor(StandardTemplateParams p) {
+        /**
+         * Gets the background color, with {@link #COLOR_DEFAULT} being a valid return value,
+         * which must be resolved by the caller before being used.
+         */
+        private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
             if (isColorized(p)) {
                 return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : getRawColor(p);
             } else {
@@ -6526,33 +6595,17 @@
         }
 
         /**
-         * Gets a neutral color that can be used for icons or similar that should not stand out.
-         * @param p the template params to inflate this with
+         * Same as {@link #getUnresolvedBackgroundColor(StandardTemplateParams)} except that it
+         * also resolves the default color to the background.
          */
-        private int getNeutralColor(StandardTemplateParams p) {
-            if (isColorized(p)) {
-                return getSecondaryTextColor(p);
-            } else {
-                return resolveNeutralColor();
-            }
-        }
-
-        /**
-         * Same as getBackgroundColor but also resolved the default color to the background.
-         * @param p the template params to inflate this with
-         */
-        private int resolveBackgroundColor(StandardTemplateParams p) {
-            int backgroundColor = getBackgroundColor(p);
+        private @ColorInt int getBackgroundColor(StandardTemplateParams p) {
+            int backgroundColor = getUnresolvedBackgroundColor(p);
             if (backgroundColor == COLOR_DEFAULT) {
-                backgroundColor = obtainBackgroundColor();
+                backgroundColor = getDefaultBackgroundColor();
             }
             return backgroundColor;
         }
 
-        private boolean shouldTintActionButtons() {
-            return mTintActionButtons;
-        }
-
         private boolean textColorsNeedInversion() {
             if (mStyle == null || !MediaStyle.class.equals(mStyle.getClass())) {
                 return false;
@@ -6570,7 +6623,7 @@
          *
          * @hide
          */
-        public void setColorPalette(int backgroundColor, int foregroundColor) {
+        public void setColorPalette(@ColorInt int backgroundColor, @ColorInt int foregroundColor) {
             mBackgroundColor = backgroundColor;
             mForegroundColor = foregroundColor;
             mTextColorsAreForBackground = COLOR_INVALID;
@@ -8200,16 +8253,14 @@
                         TypedValue.COMPLEX_UNIT_DIP);
             }
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
-                    mBuilder.isColorized(p)
-                            ? mBuilder.getPrimaryTextColor(p)
-                            : mBuilder.resolveContrastColor(p));
+                    mBuilder.getSmallIconColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
                     mBuilder.getPrimaryTextColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content, "setMessageTextColor",
                     mBuilder.getSecondaryTextColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content,
                     "setNotificationBackgroundColor",
-                    mBuilder.resolveBackgroundColor(p));
+                    mBuilder.getBackgroundColor(p));
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed",
                     isCollapsed);
             contentView.setIcon(R.id.status_bar_latest_event_content, "setAvatarReplacement",
@@ -8964,14 +9015,7 @@
 
             // If the action buttons should not be tinted, then just use the default
             // notification color. Otherwise, just use the passed-in color.
-            Resources resources = mBuilder.mContext.getResources();
-            Configuration currentConfig = resources.getConfiguration();
-            boolean inNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
-                    == Configuration.UI_MODE_NIGHT_YES;
-            int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized(p)
-                    ? getActionColor(p)
-                    : ContrastColorUtil.resolveColor(mBuilder.mContext,
-                            Notification.COLOR_DEFAULT, inNightMode);
+            int tintColor = mBuilder.getStandardActionColor(p);
 
             container.setDrawableTint(buttonId, false, tintColor,
                     PorterDuff.Mode.SRC_ATOP);
@@ -9027,11 +9071,6 @@
             return view;
         }
 
-        private int getActionColor(StandardTemplateParams p) {
-            return mBuilder.isColorized(p) ? mBuilder.getPrimaryTextColor(p)
-                    : mBuilder.resolveContrastColor(p);
-        }
-
         private RemoteViews makeMediaBigContentView() {
             final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
             // Dont add an expanded view if there is no more content to be revealed
@@ -9373,7 +9412,6 @@
                     .hideLargeIcon(true)
                     .text(text)
                     .summaryText(mBuilder.processLegacyText(mVerificationText));
-            // TODO(b/179178086): hide the snooze button
             RemoteViews contentView = mBuilder.applyStandardTemplate(
                     mBuilder.getCallLayoutResource(), p, null /* result */);
 
@@ -9390,11 +9428,9 @@
 
             // Bind some custom CallLayout properties
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
-                    mBuilder.isColorized(p)
-                            ? mBuilder.getPrimaryTextColor(p)
-                            : mBuilder.resolveContrastColor(p));
+                    mBuilder.getSmallIconColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content,
-                    "setNotificationBackgroundColor", mBuilder.resolveBackgroundColor(p));
+                    "setNotificationBackgroundColor", mBuilder.getBackgroundColor(p));
             contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
                     mBuilder.mN.mLargeIcon);
             contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 1ff64db..e0e9b62 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -73,6 +73,7 @@
 per-file Fragment.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *Task* = file:/services/core/java/com/android/server/wm/OWNERS
 per-file Window* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ConfigurationController.java = file:/services/core/java/com/android/server/wm/OWNERS
 
 # TODO(b/174932174): determine the ownership of KeyguardManager.java
 
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index ea7eab2..358ce6a 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -202,7 +202,7 @@
         }
         if (in.readInt() != 0) {
             mUserActions = new ArrayList<>();
-            in.readParcelableList(mUserActions, RemoteAction.class.getClassLoader());
+            in.readTypedList(mUserActions, RemoteAction.CREATOR);
         }
         if (in.readInt() != 0) {
             mSourceRectHint = Rect.CREATOR.createFromParcel(in);
@@ -386,7 +386,7 @@
         }
         if (mUserActions != null) {
             out.writeInt(1);
-            out.writeParcelableList(mUserActions, 0);
+            out.writeTypedList(mUserActions, 0);
         } else {
             out.writeInt(0);
         }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e16e40b..43c14a9 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -71,7 +71,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutManager;
 import android.content.pm.verify.domain.DomainVerificationManager;
-import android.content.pm.verify.domain.DomainVerificationManagerImpl;
 import android.content.pm.verify.domain.IDomainVerificationManager;
 import android.content.res.Resources;
 import android.content.rollback.RollbackManagerFrameworkInitializer;
@@ -1422,7 +1421,6 @@
                     }
                 });
 
-        // TODO(b/159952358): Only register this service for the domain verification agent?
         registerService(Context.DOMAIN_VERIFICATION_SERVICE, DomainVerificationManager.class,
                 new CachedServiceFetcher<DomainVerificationManager>() {
                     @Override
@@ -1432,7 +1430,7 @@
                                 Context.DOMAIN_VERIFICATION_SERVICE);
                         IDomainVerificationManager service =
                                 IDomainVerificationManager.Stub.asInterface(binder);
-                        return new DomainVerificationManagerImpl(context, service);
+                        return new DomainVerificationManager(context, service);
                     }
                 });
 
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 3abba43..0a8a734 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -16,9 +16,9 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -35,6 +35,8 @@
 import com.android.internal.util.ContrastColorUtil;
 
 import java.io.FileOutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -50,6 +52,13 @@
  * or {@link WallpaperColors#getTertiaryColor()}.
  */
 public final class WallpaperColors implements Parcelable {
+    /**
+     * @hide
+     */
+    @IntDef(prefix = "HINT_", value = {HINT_SUPPORTS_DARK_TEXT, HINT_SUPPORTS_DARK_THEME},
+            flag = true)
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ColorsHints {}
 
     private static final boolean DEBUG_DARK_PIXELS = false;
 
@@ -57,18 +66,14 @@
      * Specifies that dark text is preferred over the current wallpaper for best presentation.
      * <p>
      * eg. A launcher may set its text color to black if this flag is specified.
-     * @hide
      */
-    @SystemApi
     public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
 
     /**
      * Specifies that dark theme is preferred over the current wallpaper for best presentation.
      * <p>
      * eg. A launcher may set its drawer color to black if this flag is specified.
-     * @hide
      */
-    @SystemApi
     public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
 
     /**
@@ -229,15 +234,12 @@
      * @param primaryColor Primary color.
      * @param secondaryColor Secondary color.
      * @param tertiaryColor Tertiary color.
-     * @param colorHints A combination of WallpaperColor hints.
-     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
+     * @param colorHints A combination of color hints.
      * @see WallpaperColors#fromBitmap(Bitmap)
      * @see WallpaperColors#fromDrawable(Drawable)
-     * @hide
      */
-    @SystemApi
     public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
-            @Nullable Color tertiaryColor, int colorHints) {
+            @Nullable Color tertiaryColor, @ColorsHints int colorHints) {
 
         if (primaryColor == null) {
             throw new IllegalArgumentException("Primary color should never be null.");
@@ -268,13 +270,14 @@
      *
      * @param populationByColor Map with keys of colors, and value representing the number of
      *                          occurrences of color in the wallpaper.
-     * @param colorHints        A combination of WallpaperColor hints.
+     * @param colorHints        A combination of color hints.
      * @hide
      * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
      * @see WallpaperColors#fromBitmap(Bitmap)
      * @see WallpaperColors#fromDrawable(Drawable)
      */
-    public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor, int colorHints) {
+    public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor,
+            @ColorsHints int colorHints) {
         mAllColors = populationByColor;
 
         ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList(
@@ -386,27 +389,14 @@
     }
 
     /**
-     * Combination of WallpaperColor hints.
-     *
-     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
-     * @return True if dark text is supported.
-     * @hide
+     * Returns the color hints for this instance.
+     * @return The color hints.
      */
-    @SystemApi
-    public int getColorHints() {
+    public @ColorsHints int getColorHints() {
         return mColorHints;
     }
 
     /**
-     * @param colorHints Combination of WallpaperColors hints.
-     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
-     * @hide
-     */
-    public void setColorHints(int colorHints) {
-        mColorHints = colorHints;
-    }
-
-    /**
      * Checks if image is bright and clean enough to support light text.
      *
      * @param source What to read.
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 721a444..cccc929 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -585,6 +585,9 @@
      * @param intent The received intent as per {@link #onReceive}.
      */
     public void onEnabled(@NonNull Context context, @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onEnabled() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -600,6 +603,10 @@
      */
     public @Nullable CharSequence onDisableRequested(@NonNull Context context,
             @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onDisableRequested() on user "
+                    + context.getUserId());
+        }
         return null;
     }
 
@@ -612,6 +619,9 @@
      * @param intent The received intent as per {@link #onReceive}.
      */
     public void onDisabled(@NonNull Context context, @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onDisabled() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -786,6 +796,10 @@
      * @param intent The received intent as per {@link #onReceive}.
      */
     public void onProfileProvisioningComplete(@NonNull Context context, @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onProfileProvisioningComplete() on user "
+                    + context.getUserId());
+        }
     }
 
     /**
@@ -961,6 +975,9 @@
      */
     public void onUserAdded(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle addedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserAdded() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -974,6 +991,9 @@
      */
     public void onUserRemoved(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle removedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserRemoved() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -987,6 +1007,9 @@
      */
     public void onUserStarted(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle startedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserStarted() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -1000,6 +1023,9 @@
      */
     public void onUserStopped(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle stoppedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserStopped() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -1013,6 +1039,9 @@
      */
     public void onUserSwitched(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle switchedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserSwitched() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -1104,7 +1133,8 @@
     public void onReceive(@NonNull Context context, @NonNull Intent intent) {
         String action = intent.getAction();
         if (LOCAL_LOGV) {
-            Log.v(TAG, "onReceive(): received " + action + " on user " + context.getUserId());
+            Log.v(TAG, getClass().getName() + ".onReceive(): received " + action + " on user "
+                    + context.getUserId());
         }
 
         if (ACTION_PASSWORD_CHANGED.equals(action)) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bb1ff60..0635bd0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2997,6 +2997,7 @@
      */
     // TODO(b/173541467): should it throw SecurityException if caller is not admin?
     public boolean isSafeOperation(@OperationSafetyReason int reason) {
+        throwIfParentInstance("isSafeOperation");
         if (mService == null) return false;
 
         try {
@@ -12239,8 +12240,9 @@
      *
      * @hide
      */
-    public Set<String> getDisallowedSystemApps(ComponentName admin, int userId,
-            String provisioningAction) {
+    @TestApi
+    public @NonNull Set<String> getDisallowedSystemApps(@NonNull ComponentName admin,
+            @UserIdInt int userId, @NonNull String provisioningAction) {
         try {
             return new ArraySet<>(
                     mService.getDisallowedSystemApps(admin, userId, provisioningAction));
@@ -13004,6 +13006,7 @@
      *
      * @hide
      */
+    @TestApi
     public @NonNull Set<String> getDefaultCrossProfilePackages() {
         throwIfParentInstance("getDefaultCrossProfilePackages");
         if (mService != null) {
diff --git a/core/java/android/app/assist/ActivityId.java b/core/java/android/app/assist/ActivityId.java
new file mode 100644
index 0000000..fb0d056
--- /dev/null
+++ b/core/java/android/app/assist/ActivityId.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.assist;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.service.contentcapture.ContentCaptureService;
+import android.view.contentcapture.ContentCaptureContext;
+import android.view.translation.UiTranslationManager;
+
+import com.android.internal.annotations.Immutable;
+
+/**
+ * The class is used to identify an instance of an Activity. The system provides this to services
+ * that need to request operations on a specific Activity. For example, the system provides this in
+ * {@link ContentCaptureContext} to {@link ContentCaptureService} which can use it to issue requests
+ * like {@link UiTranslationManager#startTranslation}.
+ *
+ * @hide
+ */
+@Immutable
+@SystemApi
+public class ActivityId {
+
+    /**
+     * The identifier of the task this activity is in.
+     */
+    private final int mTaskId;
+    /**
+     * The identifier of the activity.
+     */
+    @Nullable
+    private final IBinder mActivityId;
+
+    /**
+     * @hide
+     */
+    public ActivityId(int taskId, @Nullable IBinder activityId) {
+        mTaskId = taskId;
+        mActivityId = activityId;
+    }
+
+    /**
+     * @hide
+     */
+    public ActivityId(@NonNull Parcel source) {
+        mTaskId = source.readInt();
+        mActivityId = source.readStrongBinder();
+    }
+
+    /**
+     * The identifier of the task this activity is in.
+     * @hide
+     */
+    @TestApi
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * The identifier of the activity. In some case, this value may be null, e.g. the child session
+     * of content capture.
+     * @hide
+     */
+    @Nullable
+    @TestApi
+    public IBinder getToken() {
+        return mActivityId;
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(@NonNull Parcel dest, int parcelableFlags) {
+        dest.writeInt(mTaskId);
+        dest.writeStrongBinder(mActivityId);
+    }
+
+    @Override
+    public String toString() {
+        return "ActivityId { taskId = " + mTaskId + ", activityId = " + mActivityId + " }";
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ActivityId that = (ActivityId) o;
+        if (mTaskId != that.mTaskId) {
+            return false;
+        }
+        return mActivityId != null
+                ? mActivityId.equals(that.mActivityId)
+                : that.mActivityId == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mTaskId;
+        result = 31 * result + (mActivityId != null ? mActivityId.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 22492cc..94a4fde0 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -403,7 +403,7 @@
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
         FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this,
                 mOperationType);
-        if (!isDeviceToDeviceMigration() && !backupScheme.isFullBackupContentEnabled()) {
+        if (!backupScheme.isFullBackupEnabled(data.getTransportFlags())) {
             return;
         }
 
@@ -911,7 +911,7 @@
         }
 
         FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this, mOperationType);
-        if (!bs.isFullBackupContentEnabled()) {
+        if (!bs.isFullRestoreEnabled()) {
             if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
                 Log.v(FullBackup.TAG_XML_PARSER,
                         "onRestoreFile \"" + destination.getCanonicalPath()
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 829b6cd..9b543b5 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -99,6 +99,8 @@
     public static final String FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER = "deviceToDeviceTransfer";
     public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
             "fakeClientSideEncryption";
+    private static final String FLAG_DISABLE_IF_NO_ENCRYPTION_CAPABILITIES
+            = "disableIfNoEncryptionCapabilities";
 
     /**
      * When  this change is enabled, include / exclude rules specified via
@@ -307,6 +309,10 @@
         // lazy initialized, only when needed
         private StorageVolume[] mVolumes = null;
 
+        // Properties the transport must have (e.g. encryption) for the operation to go ahead.
+        @Nullable private Integer mRequiredTransportFlags;
+        @Nullable private Boolean mIsUsingNewScheme;
+
         /**
          * Parse out the semantic domains into the correct physical location.
          */
@@ -453,6 +459,35 @@
             }
         }
 
+        boolean isFullBackupEnabled(int transportFlags) {
+            try {
+                if (isUsingNewScheme()) {
+                    int requiredTransportFlags = getRequiredTransportFlags();
+                    // All bits that are set in requiredTransportFlags must be set in
+                    // transportFlags.
+                    return (transportFlags & requiredTransportFlags) == requiredTransportFlags;
+                }
+            } catch (IOException | XmlPullParserException e) {
+                Slog.w(TAG, "Failed to interpret the backup scheme: " + e);
+                return false;
+            }
+
+            return isFullBackupContentEnabled();
+        }
+
+        boolean isFullRestoreEnabled() {
+            try {
+                if (isUsingNewScheme()) {
+                    return true;
+                }
+            } catch (IOException | XmlPullParserException e) {
+                Slog.w(TAG, "Failed to interpret the backup scheme: " + e);
+                return false;
+            }
+
+            return isFullBackupContentEnabled();
+        }
+
         boolean isFullBackupContentEnabled() {
             if (mFullBackupContent < 0) {
                 // android:fullBackupContent="false", bail.
@@ -491,10 +526,30 @@
             return mExcludes;
         }
 
+        private synchronized int getRequiredTransportFlags()
+                throws IOException, XmlPullParserException {
+            if (mRequiredTransportFlags == null) {
+                maybeParseBackupSchemeLocked();
+            }
+
+            return mRequiredTransportFlags;
+        }
+
+        private synchronized boolean isUsingNewScheme()
+                throws IOException, XmlPullParserException {
+            if (mIsUsingNewScheme == null) {
+                maybeParseBackupSchemeLocked();
+            }
+
+            return mIsUsingNewScheme;
+        }
+
         private void maybeParseBackupSchemeLocked() throws IOException, XmlPullParserException {
             // This not being null is how we know that we've tried to parse the xml already.
             mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
             mExcludes = new ArraySet<PathWithRequiredFlags>();
+            mRequiredTransportFlags = 0;
+            mIsUsingNewScheme = false;
 
             if (mFullBackupContent == 0 && mDataExtractionRules == 0) {
                 // No scheme specified via either new or legacy config, will copy everything.
@@ -535,12 +590,14 @@
                 }
                 if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
                     // Found configuration in the new config, we will use it.
+                    mIsUsingNewScheme = true;
                     return;
                 }
             }
 
             if (operationType == OperationType.MIGRATION
                     && CompatChanges.isChangeEnabled(IGNORE_FULL_BACKUP_CONTENT_IN_D2D)) {
+                mIsUsingNewScheme = true;
                 return;
             }
 
@@ -584,13 +641,24 @@
                     continue;
                 }
 
-                // TODO(b/180523028): Parse required attributes for rules (e.g. encryption).
+                parseRequiredTransportFlags(parser, configSection);
                 parseRules(parser, excludes, includes, Optional.of(0), configSection);
             }
 
             logParsingResults(excludes, includes);
         }
 
+        private void parseRequiredTransportFlags(XmlPullParser parser,
+                @ConfigSection String configSection) {
+            if (ConfigSection.CLOUD_BACKUP.equals(configSection)) {
+                String encryptionAttribute = parser.getAttributeValue(/* namespace */ null,
+                        FLAG_DISABLE_IF_NO_ENCRYPTION_CAPABILITIES);
+                if ("true".equals(encryptionAttribute)) {
+                    mRequiredTransportFlags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+                }
+            }
+        }
+
         @VisibleForTesting
         public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
                                                    Set<PathWithRequiredFlags> excludes,
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 73a9cec..94ab0dd 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -71,6 +71,7 @@
     private boolean mIsForward;
     private ProfilerInfo mProfilerInfo;
     private IBinder mAssistToken;
+    private IBinder mShareableActivityToken;
     /**
      * It is only non-null if the process is the first time to launch activity. It is only an
      * optimization for quick look up of the interface so the field is ignored for comparison.
@@ -95,7 +96,7 @@
         ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                 mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                 mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
-                client, mAssistToken, mFixedRotationAdjustments);
+                client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken);
         client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -119,7 +120,7 @@
             List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
             boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
             IActivityClientController activityClientController,
-            FixedRotationAdjustments fixedRotationAdjustments) {
+            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
         if (instance == null) {
             instance = new LaunchActivityItem();
@@ -127,7 +128,7 @@
         setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
                 voiceInteractor, procState, state, persistentState, pendingResults,
                 pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
-                activityClientController, fixedRotationAdjustments);
+                activityClientController, fixedRotationAdjustments, shareableActivityToken);
 
         return instance;
     }
@@ -135,7 +136,7 @@
     @Override
     public void recycle() {
         setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
-                null, false, null, null, null, null);
+                null, false, null, null, null, null, null);
         ObjectPool.recycle(this);
     }
 
@@ -164,6 +165,7 @@
         dest.writeStrongBinder(mAssistToken);
         dest.writeStrongInterface(mActivityClientController);
         dest.writeTypedObject(mFixedRotationAdjustments, flags);
+        dest.writeStrongBinder(mShareableActivityToken);
     }
 
     /** Read from Parcel. */
@@ -181,7 +183,7 @@
                 in.readTypedObject(ProfilerInfo.CREATOR),
                 in.readStrongBinder(),
                 IActivityClientController.Stub.asInterface(in.readStrongBinder()),
-                in.readTypedObject(FixedRotationAdjustments.CREATOR));
+                in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder());
     }
 
     public static final @NonNull Creator<LaunchActivityItem> CREATOR =
@@ -219,7 +221,8 @@
                 && mIsForward == other.mIsForward
                 && Objects.equals(mProfilerInfo, other.mProfilerInfo)
                 && Objects.equals(mAssistToken, other.mAssistToken)
-                && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
+                && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments)
+                && Objects.equals(mShareableActivityToken, other.mShareableActivityToken);
     }
 
     @Override
@@ -241,6 +244,7 @@
         result = 31 * result + Objects.hashCode(mProfilerInfo);
         result = 31 * result + Objects.hashCode(mAssistToken);
         result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
+        result = 31 * result + Objects.hashCode(mShareableActivityToken);
         return result;
     }
 
@@ -277,7 +281,8 @@
                 + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
                 + ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions
                 + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken
-                + ",rotationAdj=" + mFixedRotationAdjustments + "}";
+                + ",rotationAdj=" + mFixedRotationAdjustments
+                + ",shareableActivityToken=" + mShareableActivityToken + "}";
     }
 
     // Using the same method to set and clear values to make sure we don't forget anything
@@ -288,7 +293,7 @@
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
             ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
             IBinder assistToken, IActivityClientController activityClientController,
-            FixedRotationAdjustments fixedRotationAdjustments) {
+            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
         instance.mIntent = intent;
         instance.mIdent = ident;
         instance.mInfo = info;
@@ -308,5 +313,6 @@
         instance.mAssistToken = assistToken;
         instance.mActivityClientController = activityClientController;
         instance.mFixedRotationAdjustments = fixedRotationAdjustments;
+        instance.mShareableActivityToken = shareableActivityToken;
     }
 }
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 1d5dc1d..098d8b6 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -16,6 +16,8 @@
 
 package android.app.usage;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -28,8 +30,11 @@
 import android.net.ConnectivityManager;
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsService;
+import android.net.Network;
 import android.net.NetworkStack;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTemplate;
+import android.net.UnderlyingNetworkInfo;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.net.netstats.provider.NetworkStatsProvider;
 import android.os.Binder;
@@ -48,6 +53,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetworkIdentityUtils;
 
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -633,6 +639,50 @@
         return template;
     }
 
+    /**
+     *  Notify {@code NetworkStatsService} about network status changed.
+     *
+     *  Notifies NetworkStatsService of network state changes for data usage accounting purposes.
+     *
+     *  To avoid races that attribute data usage to wrong network, such as new network with
+     *  the same interface after SIM hot-swap, this function will not return until
+     *  {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
+     *  all data sources.
+     *
+     * @param defaultNetworks the list of all networks that could be used by network traffic that
+     *                        does not explicitly select a network.
+     * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for
+     *                              each network that is currently connected.
+     * @param activeIface the active (i.e., connected) default network interface for the calling
+     *                    uid. Used to determine on which network future calls to
+     *                    {@link android.net.TrafficStats#incrementOperationCount} applies to.
+     * @param underlyingNetworkInfos the list of underlying network information for all
+     *                               currently-connected VPNs.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
+    public void notifyNetworkStatus(
+            @NonNull List<Network> defaultNetworks,
+            @NonNull List<NetworkStateSnapshot> networkStateSnapshots,
+            @Nullable String activeIface,
+            @NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) {
+        try {
+            Objects.requireNonNull(defaultNetworks);
+            Objects.requireNonNull(networkStateSnapshots);
+            Objects.requireNonNull(underlyingNetworkInfos);
+            // TODO: Change internal namings after the name is decided.
+            mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]),
+                    networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface,
+                    underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0]));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static class CallbackHandler extends Handler {
         private final int mNetworkType;
         private final String mSubscriberId;
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 081f4fd..e6a4656 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -334,10 +334,19 @@
         public static final int LOCUS_ID_SET = 30;
 
         /**
+         * An event type denoting that a component in the package has been used (e.g. broadcast
+         * receiver, service, content provider). This generally matches up with usage that would
+         * cause an app to leave force stop. The component itself is not provided as we are only
+         * interested in whether the package is used, not the component itself.
+         * @hide
+         */
+        public static final int APP_COMPONENT_USED = 31;
+
+        /**
          * Keep in sync with the greatest event type value.
          * @hide
          */
-        public static final int MAX_EVENT_TYPE = 30;
+        public static final int MAX_EVENT_TYPE = 31;
 
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e7661db..ec94faa 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -374,6 +374,35 @@
     public static final String ACTION_SDP_RECORD =
             "android.bluetooth.device.action.SDP_RECORD";
 
+    /** @hide */
+    @IntDef(prefix = "METADATA_", value = {
+            METADATA_MANUFACTURER_NAME,
+            METADATA_MODEL_NAME,
+            METADATA_SOFTWARE_VERSION,
+            METADATA_HARDWARE_VERSION,
+            METADATA_COMPANION_APP,
+            METADATA_MAIN_ICON,
+            METADATA_IS_UNTETHERED_HEADSET,
+            METADATA_UNTETHERED_LEFT_ICON,
+            METADATA_UNTETHERED_RIGHT_ICON,
+            METADATA_UNTETHERED_CASE_ICON,
+            METADATA_UNTETHERED_LEFT_BATTERY,
+            METADATA_UNTETHERED_RIGHT_BATTERY,
+            METADATA_UNTETHERED_CASE_BATTERY,
+            METADATA_UNTETHERED_LEFT_CHARGING,
+            METADATA_UNTETHERED_RIGHT_CHARGING,
+            METADATA_UNTETHERED_CASE_CHARGING,
+            METADATA_ENHANCED_SETTINGS_UI_URI,
+            METADATA_DEVICE_TYPE,
+            METADATA_MAIN_BATTERY,
+            METADATA_MAIN_CHARGING,
+            METADATA_MAIN_LOW_BATTERY_THRESHOLD,
+            METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
+            METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
+            METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MetadataKey{}
+
     /**
      * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
      * disk usage
@@ -523,6 +552,89 @@
     public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
 
     /**
+     * Type of the Bluetooth device, must be within the list of
+     * BluetoothDevice.DEVICE_TYPE_*
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_DEVICE_TYPE = 17;
+
+    /**
+     * Battery level of the Bluetooth device, use when the Bluetooth device
+     * does not support HFP battery indicator.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_BATTERY = 18;
+
+    /**
+     * Whether the device is charging.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_CHARGING = 19;
+
+    /**
+     * The battery threshold of the Bluetooth device to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20;
+
+    /**
+     * The battery threshold of the left headset to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21;
+
+    /**
+     * The battery threshold of the right headset to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22;
+
+    /**
+     * The battery threshold of the case to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23;
+
+    /**
+     * Device type which is used in METADATA_DEVICE_TYPE
+     * Indicates this Bluetooth device is a standard Bluetooth accessory or
+     * not listed in METADATA_DEVICE_TYPE_*.
+     * @hide
+     */
+    @SystemApi
+    public static final String DEVICE_TYPE_DEFAULT = "Default";
+
+    /**
+     * Device type which is used in METADATA_DEVICE_TYPE
+     * Indicates this Bluetooth device is a watch.
+     * @hide
+     */
+    @SystemApi
+    public static final String DEVICE_TYPE_WATCH = "Watch";
+
+    /**
+     * Device type which is used in METADATA_DEVICE_TYPE
+     * Indicates this Bluetooth device is an untethered headset.
+     * @hide
+     */
+    @SystemApi
+    public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
+
+    /**
      * Broadcast Action: This intent is used to broadcast the {@link UUID}
      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
      * has been fetched. This intent is sent only when the UUIDs of the remote
@@ -2316,7 +2428,7 @@
     */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean setMetadata(int key, @NonNull byte[] value) {
+    public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
@@ -2344,7 +2456,7 @@
     @SystemApi
     @Nullable
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public byte[] getMetadata(int key) {
+    public byte[] getMetadata(@MetadataKey int key) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
@@ -2357,4 +2469,14 @@
             return null;
         }
     }
+
+    /**
+     * Get the maxinum metadata key ID.
+     *
+     * @return the last supported metadata key
+     * @hide
+     */
+    public static @MetadataKey int getMaxMetadataKey() {
+        return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD;
+    }
 }
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
index e3a130c..4e64dbe 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
@@ -22,7 +22,7 @@
 /**
  * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic
  * advertising preferences for each Bluetooth LE advertising set. Use {@link
- * AdvertisingSetParameters.Builder} to create an instance of this class.
+ * PeriodicAdvertisingParameters.Builder} to create an instance of this class.
  */
 public final class PeriodicAdvertisingParameters implements Parcelable {
 
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 102c98f..17bdd42 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -60,6 +60,10 @@
     /**
      * Device profile: watch.
      *
+     * If specified, the current request may have a modified UI to highlight that the device being
+     * set up is a specific kind of device, and some extra permissions may be granted to the app
+     * as a result.
+     *
      * @see AssociationRequest.Builder#setDeviceProfile
      */
     public static final String DEVICE_PROFILE_WATCH =
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f3a4e1f..02e86cd 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -370,6 +370,15 @@
     /***********    Hidden flags below this line ***********/
 
     /**
+     * Flag for {@link #bindService}: This flag is only intended to be used by the system to
+     * indicate that a service binding is not considered as real package component usage and should
+     * not generate a {@link android.app.usage.UsageEvents.Event#APP_COMPONENT_USED} event in usage
+     * stats.
+     * @hide
+     */
+    public static final int BIND_NOT_APP_COMPONENT_USAGE = 0x00008000;
+
+    /**
      * Flag for {@link #bindService}: allow the process hosting the target service to be treated
      * as if it's as important as a perceptible app to the user and avoid the oom killer killing
      * this process in low memory situations until there aren't any other processes left but the
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d53d20a..d352b27 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6755,6 +6755,12 @@
      */
     private static final int LOCAL_FLAG_FROM_PROTECTED_COMPONENT = 1 << 2;
 
+    /**
+     * Local flag indicating this instance had unfiltered extras copied into it. This could be
+     * from either {@link #putExtras(Intent)} when an unparceled Intent is provided or {@link
+     * #putExtras(Bundle)} when the provided Bundle has not been unparceled.
+     */
+    private static final int LOCAL_FLAG_UNFILTERED_EXTRAS = 1 << 3;
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
@@ -10009,6 +10015,15 @@
                 mExtras.putAll(src.mExtras);
             }
         }
+        // If the provided Intent was unparceled and this is not an Intent delivered to a protected
+        // component then mark the extras as unfiltered. An Intent delivered to a protected
+        // component had to come from a trusted component, and if unfiltered data was copied to the
+        // delivered Intent then it would have been reported when that Intent left the sending
+        // process.
+        if ((src.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+                && (src.mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+            mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
+        }
         return this;
     }
 
@@ -10023,6 +10038,10 @@
      * @see #removeExtra
      */
     public @NonNull Intent putExtras(@NonNull Bundle extras) {
+        // If the provided Bundle has not yet been unparceled then treat this as unfiltered extras.
+        if (extras.isParcelled()) {
+            mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
+        }
         if (mExtras == null) {
             mExtras = new Bundle();
         }
@@ -11328,10 +11347,13 @@
         }
 
         // Detect cases where we're about to launch a potentially unsafe intent
-        if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
-                && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0
-                && StrictMode.vmUnsafeIntentLaunchEnabled()) {
-            StrictMode.onUnsafeIntentLaunch(this);
+        if (StrictMode.vmUnsafeIntentLaunchEnabled()) {
+            if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+                    && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+                StrictMode.onUnsafeIntentLaunch(this);
+            } else if ((mLocalFlags & LOCAL_FLAG_UNFILTERED_EXTRAS) != 0) {
+                StrictMode.onUnsafeIntentLaunch(this);
+            }
         }
     }
 
diff --git a/core/java/android/content/pm/AppSearchPerson.java b/core/java/android/content/pm/AppSearchPerson.java
index d70ac91..66295eb 100644
--- a/core/java/android/content/pm/AppSearchPerson.java
+++ b/core/java/android/content/pm/AppSearchPerson.java
@@ -42,7 +42,7 @@
     public static final String KEY_IS_BOT = "isBot";
     public static final String KEY_IS_IMPORTANT = "isImportant";
 
-    private AppSearchPerson(@NonNull GenericDocument document) {
+    public AppSearchPerson(@NonNull GenericDocument document) {
         super(document);
     }
 
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index ebe202b..5af3b5a 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -28,7 +28,6 @@
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
 
@@ -53,17 +52,23 @@
     /** The name of the schema type for {@link ShortcutInfo} documents.*/
     public static final String SCHEMA_TYPE = "Shortcut";
 
-    public static final String KEY_PACKAGE_NAME = "packageName";
     public static final String KEY_ACTIVITY = "activity";
-    public static final String KEY_TITLE = "title";
-    public static final String KEY_TEXT = "text";
+    public static final String KEY_SHORT_LABEL = "shortLabel";
+    public static final String KEY_SHORT_LABEL_RES_ID = "shortLabelResId";
+    public static final String KEY_SHORT_LABEL_RES_NAME = "shortLabelResName";
+    public static final String KEY_LONG_LABEL = "longLabel";
+    public static final String KEY_LONG_LABEL_RES_ID = "longLabelResId";
+    public static final String KEY_LONG_LABEL_RES_NAME = "longLabelResName";
     public static final String KEY_DISABLED_MESSAGE = "disabledMessage";
+    public static final String KEY_DISABLED_MESSAGE_RES_ID = "disabledMessageResId";
+    public static final String KEY_DISABLED_MESSAGE_RES_NAME = "disabledMessageResName";
     public static final String KEY_CATEGORIES = "categories";
     public static final String KEY_INTENTS = "intents";
     public static final String KEY_INTENT_PERSISTABLE_EXTRAS = "intentPersistableExtras";
     public static final String KEY_PERSON = "person";
     public static final String KEY_LOCUS_ID = "locusId";
     public static final String KEY_RANK = "rank";
+    public static final String KEY_IMPLICIT_RANK = "implicitRank";
     public static final String KEY_EXTRAS = "extras";
     public static final String KEY_FLAGS = "flags";
     public static final String KEY_ICON_RES_ID = "iconResId";
@@ -73,36 +78,62 @@
     public static final String KEY_DISABLED_REASON = "disabledReason";
 
     public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-            .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_PACKAGE_NAME)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
-                    .build()
-
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
+            .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
                     .build()
 
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TITLE)
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
                     .build()
 
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TEXT)
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_SHORT_LABEL_RES_ID)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL_RES_NAME)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
                     .build()
 
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_LONG_LABEL_RES_ID)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL_RES_NAME)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_MESSAGE)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
                     .build()
 
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(
+                    KEY_DISABLED_MESSAGE_RES_ID)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
+                    KEY_DISABLED_MESSAGE_RES_NAME)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CATEGORIES)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
@@ -135,6 +166,10 @@
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .build()
 
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_IMPLICIT_RANK)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
             ).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_EXTRAS)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .build()
@@ -183,13 +218,21 @@
         Objects.requireNonNull(shortcutInfo);
         return new Builder(shortcutInfo.getId())
                 .setActivity(shortcutInfo.getActivity())
-                .setPackageName(shortcutInfo.getPackage())
-                .setTitle(shortcutInfo.getShortLabel())
-                .setText(shortcutInfo.getLongLabel())
+                .setNamespace(shortcutInfo.getPackage())
+                .setShortLabel(shortcutInfo.getShortLabel())
+                .setShortLabelResId(shortcutInfo.getShortLabelResourceId())
+                .setShortLabelResName(shortcutInfo.getTitleResName())
+                .setLongLabel(shortcutInfo.getLongLabel())
+                .setLongLabelResId(shortcutInfo.getLongLabelResourceId())
+                .setLongLabelResName(shortcutInfo.getTextResName())
                 .setDisabledMessage(shortcutInfo.getDisabledMessage())
+                .setDisabledMessageResId(shortcutInfo.getDisabledMessageResourceId())
+                .setDisabledMessageResName(shortcutInfo.getDisabledMessageResName())
                 .setCategories(shortcutInfo.getCategories())
                 .setIntents(shortcutInfo.getIntents())
                 .setRank(shortcutInfo.getRank())
+                .setImplicitRank(shortcutInfo.getImplicitRank()
+                        | (shortcutInfo.isRankChanged() ? ShortcutInfo.RANK_CHANGED_BIT : 0))
                 .setExtras(shortcutInfo.getExtras())
                 .setCreationTimestampMillis(shortcutInfo.getLastChangedTimestamp())
                 .setFlags(shortcutInfo.getFlags())
@@ -207,17 +250,8 @@
      * @hide
      */
     @NonNull
-    public ShortcutInfo toShortcutInfo() {
-        return toShortcutInfo(UserHandle.myUserId());
-    }
-
-    /**
-     * @hide
-     * TODO: This should be @SystemApi when AppSearchShortcutInfo unhides.
-     */
-    @NonNull
-    public ShortcutInfo toShortcutInfo(@UserIdInt final int userId) {
-        final String packageName = getPropertyString(KEY_PACKAGE_NAME);
+    public ShortcutInfo toShortcutInfo(@UserIdInt int userId) {
+        final String packageName = getNamespace();
         final String activityString = getPropertyString(KEY_ACTIVITY);
         final ComponentName activity = activityString == null
                 ? null : ComponentName.unflattenFromString(activityString);
@@ -228,15 +262,24 @@
         // @hide and @UnsupportedAppUsage, we could migrate existing usage in platform with
         // LauncherApps#getShortcutIconDrawable instead.
         final Icon icon = null;
-        final String title = getPropertyString(KEY_TITLE);
-        final String text = getPropertyString(KEY_TEXT);
+        final String shortLabel = getPropertyString(KEY_SHORT_LABEL);
+        final int shortLabelResId = (int) getPropertyLong(KEY_SHORT_LABEL_RES_ID);
+        final String shortLabelResName = getPropertyString(KEY_SHORT_LABEL_RES_NAME);
+        final String longLabel = getPropertyString(KEY_LONG_LABEL);
+        final int longLabelResId = (int) getPropertyLong(KEY_LONG_LABEL_RES_ID);
+        final String longLabelResName = getPropertyString(KEY_LONG_LABEL_RES_NAME);
         final String disabledMessage = getPropertyString(KEY_DISABLED_MESSAGE);
+        final int disabledMessageResId = (int) getPropertyLong(KEY_DISABLED_MESSAGE_RES_ID);
+        final String disabledMessageResName = getPropertyString(KEY_DISABLED_MESSAGE_RES_NAME);
         final String[] categories = getPropertyStringArray(KEY_CATEGORIES);
         final Set<String> categoriesSet = categories == null
-                ? new ArraySet<>() : new ArraySet<>(Arrays.asList(categories));
+                ? null : new ArraySet<>(Arrays.asList(categories));
         final String[] intentsStrings = getPropertyStringArray(KEY_INTENTS);
         final Intent[] intents = intentsStrings == null
-                ? null : Arrays.stream(intentsStrings).map(uri -> {
+                ? new Intent[0] : Arrays.stream(intentsStrings).map(uri -> {
+                    if (TextUtils.isEmpty(uri)) {
+                        return new Intent(Intent.ACTION_VIEW);
+                    }
                     try {
                         return Intent.parseUri(uri, /* flags =*/ 0);
                     } catch (URISyntaxException e) {
@@ -251,15 +294,18 @@
         if (intents != null) {
             for (int i = 0; i < intents.length; i++) {
                 final Intent intent = intents[i];
-                if (intent != null) {
-                    intent.replaceExtras(intentExtrases[i].size() == 0 ? null : intentExtrases[i]);
+                if (intent == null || intentExtrases == null || intentExtrases.length <= i
+                        || intentExtrases[i] == null || intentExtrases[i].size() == 0) {
+                    continue;
                 }
+                intent.replaceExtras(intentExtrases[i]);
             }
         }
         final Person[] persons = parsePerson(getPropertyDocumentArray(KEY_PERSON));
         final String locusIdString = getPropertyString(KEY_LOCUS_ID);
         final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
         final int rank = (int) getPropertyLong(KEY_RANK);
+        final int implicitRank = (int) getPropertyLong(KEY_IMPLICIT_RANK);
         final byte[] extrasByte = getPropertyBytes(KEY_EXTRAS);
         final PersistableBundle extras = transformToPersistableBundle(extrasByte);
         final int flags = parseFlags(getPropertyLongArray(KEY_FLAGS));
@@ -268,12 +314,17 @@
         final String iconUri = getPropertyString(KEY_ICON_URI);
         final String bitmapPath = getPropertyString(KEY_BITMAP_PATH);
         final int disabledReason = (int) getPropertyLong(KEY_DISABLED_REASON);
-        return new ShortcutInfo(
-                userId, getUri(), packageName, activity, icon, title, 0, null,
-                text, 0, null, disabledMessage, 0, null,
-                categoriesSet, intents, rank, extras,
+        final ShortcutInfo si = new ShortcutInfo(
+                userId, getUri(), packageName, activity, icon, shortLabel, shortLabelResId,
+                shortLabelResName, longLabel, longLabelResId, longLabelResName, disabledMessage,
+                disabledMessageResId, disabledMessageResName, categoriesSet, intents, rank, extras,
                 getCreationTimestampMillis(), flags, iconResId, iconResName, bitmapPath, iconUri,
                 disabledReason, persons, locusId, 0);
+        si.setImplicitRank(implicitRank);
+        if ((implicitRank & ShortcutInfo.RANK_CHANGED_BIT) != 0) {
+            si.setRankChanged();
+        }
+        return si;
     }
 
     /** @hide */
@@ -310,9 +361,9 @@
          * @hide
          */
         @NonNull
-        public Builder setTitle(@Nullable final CharSequence shortLabel) {
+        public Builder setShortLabel(@Nullable final CharSequence shortLabel) {
             if (!TextUtils.isEmpty(shortLabel)) {
-                setPropertyString(KEY_TITLE, Preconditions.checkStringNotEmpty(
+                setPropertyString(KEY_SHORT_LABEL, Preconditions.checkStringNotEmpty(
                         shortLabel, "shortLabel cannot be empty").toString());
             }
             return this;
@@ -322,13 +373,50 @@
          * @hide
          */
         @NonNull
-        public Builder setText(@Nullable final CharSequence longLabel) {
+        public Builder setShortLabelResId(@Nullable final int shortLabelResId) {
+            setPropertyLong(KEY_SHORT_LABEL_RES_ID, shortLabelResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setShortLabelResName(@Nullable final String shortLabelResName) {
+            if (!TextUtils.isEmpty(shortLabelResName)) {
+                setPropertyString(KEY_SHORT_LABEL_RES_NAME, shortLabelResName);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setLongLabel(@Nullable final CharSequence longLabel) {
             if (!TextUtils.isEmpty(longLabel)) {
-                setPropertyString(KEY_TEXT, Preconditions.checkStringNotEmpty(
+                setPropertyString(KEY_LONG_LABEL, Preconditions.checkStringNotEmpty(
                         longLabel, "longLabel cannot be empty").toString());
             }
             return this;
+        }
 
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setLongLabelResId(@Nullable final int longLabelResId) {
+            setPropertyLong(KEY_LONG_LABEL_RES_ID, longLabelResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setLongLabelResName(@Nullable final String longLabelResName) {
+            if (!TextUtils.isEmpty(longLabelResName)) {
+                setPropertyString(KEY_LONG_LABEL_RES_NAME, longLabelResName);
+            }
+            return this;
         }
 
         /**
@@ -347,6 +435,25 @@
          * @hide
          */
         @NonNull
+        public Builder setDisabledMessageResId(@Nullable final int disabledMessageResId) {
+            setPropertyLong(KEY_DISABLED_MESSAGE_RES_ID, disabledMessageResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setDisabledMessageResName(@Nullable final String disabledMessageResName) {
+            if (!TextUtils.isEmpty(disabledMessageResName)) {
+                setPropertyString(KEY_DISABLED_MESSAGE_RES_NAME, disabledMessageResName);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
         public Builder setCategories(@Nullable final Set<String> categories) {
             if (categories != null && !categories.isEmpty()) {
                 setPropertyString(KEY_CATEGORIES, categories.stream().toArray(String[]::new));
@@ -384,9 +491,8 @@
                 intentExtrases[i] = extras == null
                         ? new byte[0] : transformToByteArray(new PersistableBundle(extras));
             }
-
-            setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it ->
-                    it.toUri(0)).toArray(String[]::new));
+            setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it -> it.toUri(0))
+                    .toArray(String[]::new));
             setPropertyBytes(KEY_INTENT_PERSISTABLE_EXTRAS, intentExtrases);
             return this;
         }
@@ -410,10 +516,14 @@
             if (persons == null || persons.length == 0) {
                 return this;
             }
-            setPropertyDocument(KEY_PERSON,
-                    Arrays.stream(persons).map(person -> AppSearchPerson.instance(
-                            Objects.requireNonNull(person, "persons cannot contain null"))
-                    ).toArray(AppSearchPerson[]::new));
+            final GenericDocument[] documents = new GenericDocument[persons.length];
+            for (int i = 0; i < persons.length; i++) {
+                final Person person = persons[i];
+                if (person == null) continue;
+                final AppSearchPerson appSearchPerson = AppSearchPerson.instance(person);
+                documents[i] = appSearchPerson;
+            }
+            setPropertyDocument(KEY_PERSON, documents);
             return this;
         }
 
@@ -422,8 +532,7 @@
          */
         @NonNull
         public Builder setRank(final int rank) {
-            Preconditions.checkArgument((0 <= rank),
-                    "Rank cannot be negative or bigger than MAX_RANK");
+            Preconditions.checkArgument((0 <= rank), "Rank cannot be negative");
             setPropertyLong(KEY_RANK, rank);
             return this;
         }
@@ -432,6 +541,15 @@
          * @hide
          */
         @NonNull
+        public Builder setImplicitRank(final int rank) {
+            setPropertyLong(KEY_IMPLICIT_RANK, rank);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
         public Builder setExtras(@Nullable final PersistableBundle extras) {
             if (extras != null) {
                 setPropertyBytes(KEY_EXTRAS, transformToByteArray(extras));
@@ -444,7 +562,7 @@
          */
         public Builder setPackageName(@Nullable final String packageName) {
             if (!TextUtils.isEmpty(packageName)) {
-                setPropertyString(KEY_PACKAGE_NAME, packageName);
+                setNamespace(packageName);
             }
             return this;
         }
@@ -579,7 +697,14 @@
 
     @NonNull
     private static Person[] parsePerson(@Nullable final GenericDocument[] persons) {
-        return persons == null ? new Person[0] : Arrays.stream(persons).map(it ->
-                ((AppSearchPerson) it).toPerson()).toArray(Person[]::new);
+        if (persons == null) return new Person[0];
+        final Person[] ret = new Person[persons.length];
+        for (int i = 0; i < persons.length; i++) {
+            final GenericDocument document = persons[i];
+            if (document == null) continue;
+            final AppSearchPerson person = new AppSearchPerson(document);
+            ret[i] = person.toPerson();
+        }
+        return ret;
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 0aa1be9..1a5dad5 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1205,7 +1205,8 @@
             CATEGORY_SOCIAL,
             CATEGORY_NEWS,
             CATEGORY_MAPS,
-            CATEGORY_PRODUCTIVITY
+            CATEGORY_PRODUCTIVITY,
+            CATEGORY_ACCESSIBILITY
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Category {
@@ -1281,6 +1282,13 @@
     public static final int CATEGORY_PRODUCTIVITY = 7;
 
     /**
+     * Category for apps which are primarily accessibility apps, such as screen-readers.
+     *
+     * @see #category
+     */
+    public static final int CATEGORY_ACCESSIBILITY = 8;
+
+    /**
      * Return a concise, localized title for the given
      * {@link ApplicationInfo#category} value, or {@code null} for unknown
      * values such as {@link #CATEGORY_UNDEFINED}.
@@ -1305,6 +1313,8 @@
                 return context.getText(com.android.internal.R.string.app_category_maps);
             case ApplicationInfo.CATEGORY_PRODUCTIVITY:
                 return context.getText(com.android.internal.R.string.app_category_productivity);
+            case ApplicationInfo.CATEGORY_ACCESSIBILITY:
+                return context.getText(com.android.internal.R.string.app_category_accessibility);
             default:
                 return null;
         }
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index b290679..48b634e 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.AppOpsManager.Mode;
 import android.content.ComponentName;
@@ -418,6 +419,7 @@
      *
      * @hide
      */
+    @TestApi
     public boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
         try {
             return mService.canConfigureInteractAcrossProfiles(packageName);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 29dea6b..d79b66c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3584,30 +3584,18 @@
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
      * the requisite kernel support to support incremental delivery aka Incremental FileSystem.
      *
-     * @see IncrementalManager#isFeatureEnabled
-     * @hide
-     *
-     * @deprecated Use {@link #FEATURE_INCREMENTAL_DELIVERY_VERSION} instead.
-     */
-    @Deprecated
-    @SystemApi
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_INCREMENTAL_DELIVERY =
-            "android.software.incremental_delivery";
-
-    /**
-     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * feature not present - IncFs is not present on the device.
      * 1 - IncFs v1, core features, no PerUid support. Optional in R.
      * 2 - IncFs v2, PerUid support, fs-verity support. Required in S.
      *
+     * @see IncrementalManager#isFeatureEnabled
      * @see IncrementalManager#getVersion()
      * @hide
      */
     @SystemApi
     @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION =
-            "android.software.incremental_delivery_version";
+    public static final String FEATURE_INCREMENTAL_DELIVERY =
+            "android.software.incremental_delivery";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
@@ -3656,17 +3644,6 @@
     public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
 
     /**
-     * Feature for {@link android.view.WindowManager.LayoutParams.backgroundBlurRedius} and
-     * {@link android.graphics.drawable.BackgroundBlurDrawable}: the device supports cross-layer
-     * blurring.
-     *
-     * @hide
-     */
-    @SystemApi
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
      * a Keystore implementation that can only enforce limited use key in hardware with max usage
      * count equals to 1.
@@ -7040,7 +7017,7 @@
      * domain to an application, use
      * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
      * passing in all of the domains returned inside
-     * {@link DomainVerificationManager#getDomainVerificationUserSelection(String)}.
+     * {@link DomainVerificationManager#getDomainVerificationUserState(String)}.
      *
      * @hide
      */
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 7ecb112..7696cbe 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -42,6 +42,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 
 import libcore.io.IoUtils;
@@ -161,18 +162,20 @@
         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         intentFilter.addDataScheme("package");
-        mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null);
+        Handler handler = BackgroundThread.getHandler();
+        mContext.registerReceiverAsUser(
+                mPackageReceiver, UserHandle.ALL, intentFilter, null, handler);
 
         // Register for events related to sdcard installation.
         IntentFilter sdFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mExternalReceiver, sdFilter);
+        mContext.registerReceiver(mExternalReceiver, sdFilter, null, handler);
 
         // Register for user-related events
         IntentFilter userFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_USER_REMOVED);
-        mContext.registerReceiver(mUserRemovedReceiver, userFilter);
+        mContext.registerReceiver(mUserRemovedReceiver, userFilter, null, handler);
     }
 
     private void handlePackageEvent(Intent intent, int userId) {
@@ -265,7 +268,7 @@
 
     public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) {
         if (handler == null) {
-            handler = new Handler(mContext.getMainLooper());
+            handler = BackgroundThread.getHandler();
         }
         synchronized (this) {
             mHandler = handler;
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 5f80ba1..275e81c 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -68,7 +68,8 @@
 
     private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
 
-    private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
+    /** @hide */
+    public static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
 
     /** @hide */
     public static final int RANK_NOT_SET = Integer.MAX_VALUE;
@@ -1595,6 +1596,9 @@
      */
     @Nullable
     public Intent[] getIntents() {
+        if (mIntents == null) {
+            return null;
+        }
         final Intent[] ret = new Intent[mIntents.length];
 
         for (int i = 0; i < ret.length; i++) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 2ea24f7..6f478ac 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -155,6 +155,7 @@
         alias.nonLocalizedLabel = target.nonLocalizedLabel;
         alias.launchMode = target.launchMode;
         alias.lockTaskLaunchMode = target.lockTaskLaunchMode;
+        alias.documentLaunchMode = target.documentLaunchMode;
         alias.descriptionRes = target.descriptionRes;
         alias.screenOrientation = target.screenOrientation;
         alias.taskAffinity = target.taskAffinity;
@@ -179,7 +180,6 @@
 //        alias.exported = target.exported;
 //        alias.permission = target.permission;
 //        alias.splitName = target.splitName;
-//        alias.documentLaunchMode = target.documentLaunchMode;
 //        alias.persistableMode = target.persistableMode;
 //        alias.rotationAnimation = target.rotationAnimation;
 //        alias.colorMode = target.colorMode;
diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS
index d302b0a..cf7e689 100644
--- a/core/java/android/content/pm/permission/OWNERS
+++ b/core/java/android/content/pm/permission/OWNERS
@@ -1,10 +1,8 @@
 # Bug component: 137825
 
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
 toddke@android.com
 toddke@google.com
 patb@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
-zhanghai@google.com
-evanseverson@google.com
-ntmyren@google.com
+
diff --git a/core/java/android/content/pm/verify/domain/DomainOwner.java b/core/java/android/content/pm/verify/domain/DomainOwner.java
index b050f5d..5bf2c09 100644
--- a/core/java/android/content/pm/verify/domain/DomainOwner.java
+++ b/core/java/android/content/pm/verify/domain/DomainOwner.java
@@ -66,16 +66,7 @@
      * @param packageName
      *   Package name of that owns the domain.
      * @param overrideable
-     *   Whether or not this owner can be automatically overridden. If all owners for a domain are
-     *   overrideable, then calling
-     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
-     *   Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
-     *   of the owners are non-overrideable, then
-     *   {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
-     *   boolean)} must be called with false to disable all of the other owners before this domain can
-     *   be taken by a new owner through
-     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
-     *   Set, boolean)}.
+     *   Whether or not this owner can be automatically overridden.
      */
     @DataClass.Generated.Member
     public DomainOwner(
@@ -98,16 +89,9 @@
     }
 
     /**
-     * Whether or not this owner can be automatically overridden. If all owners for a domain are
-     * overrideable, then calling
-     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
-     * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
-     * of the owners are non-overrideable, then
-     * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
-     * boolean)} must be called with false to disable all of the other owners before this domain can
-     * be taken by a new owner through
-     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
-     * Set, boolean)}.
+     * Whether or not this owner can be automatically overridden.
+     *
+     * @see DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)
      */
     @DataClass.Generated.Member
     public boolean isOverrideable() {
@@ -205,7 +189,7 @@
     };
 
     @DataClass.Generated(
-            time = 1614119379978L,
+            time = 1614721802044L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java",
             inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final  boolean mOverrideable\nclass DomainOwner extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genEqualsHashCode=true, genAidl=true, genToString=true)")
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
index 8095875..7c335b1 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
@@ -94,7 +94,7 @@
 
     private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
         return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
-                DomainVerificationUserSelection.class.getClassLoader());
+                DomainVerificationUserState.class.getClassLoader());
     }
 
 
@@ -105,8 +105,7 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
-    // /DomainVerificationInfo.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -321,7 +320,7 @@
     };
 
     @DataClass.Generated(
-            time = 1613002530369L,
+            time = 1614721812023L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java",
             inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate  void parcelHostToStateMap(android.os.Parcel,int)\nprivate  java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
index 11402af..f7c81bcf 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
@@ -25,6 +25,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 
 import java.util.List;
@@ -32,55 +34,63 @@
 import java.util.UUID;
 
 /**
- * System service to access the domain verification APIs.
+ * System service to access domain verification APIs.
  *
- * Allows the approved domain verification
- * agent on the device (the sole holder of
- * {@link android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}) to update the approval status
- * of domains declared by applications in their AndroidManifest.xml, to allow them to open those
- * links inside the app when selected by the user. This is done through querying
- * {@link #getDomainVerificationInfo(String)} and calling
- * {@link #setDomainVerificationStatus(UUID, Set, int)}.
- *
- * Also allows the domain preference settings (holder of
- * {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) to update the
- * preferences of the user, when they have chosen to explicitly allow an application to open links.
- * This is done through querying {@link #getDomainVerificationUserSelection(String)} and calling
- * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)} and
- * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
- *
- * @hide
+ * Applications should use {@link #getDomainVerificationUserState(String)} if necessary to
+ * check if/how they are verified for a domain, which is required starting from platform
+ * {@link android.os.Build.VERSION_CODES#S} in order to open {@link Intent}s which declare
+ * {@link Intent#CATEGORY_BROWSABLE} or no category and also match against
+ * {@link Intent#CATEGORY_DEFAULT} {@link android.content.IntentFilter}s, either through an
+ * explicit declaration of {@link Intent#CATEGORY_DEFAULT} or through the use of
+ * {@link android.content.pm.PackageManager#MATCH_DEFAULT_ONLY}, which is usually added for the
+ * caller when using {@link Context#startActivity(Intent)} and similar.
  */
-@SystemApi
 @SystemService(Context.DOMAIN_VERIFICATION_SERVICE)
-public interface DomainVerificationManager {
+public final class DomainVerificationManager {
 
     /**
-     * Extra field name for a {@link DomainVerificationRequest} for the requested packages.
-     * Passed to an the domain verification agent that handles
+     * Extra field name for a {@link DomainVerificationRequest} for the requested packages. Passed
+     * to an the domain verification agent that handles
      * {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION}.
+     *
+     * @hide
      */
-    String EXTRA_VERIFICATION_REQUEST =
+    @SystemApi
+    public static final String EXTRA_VERIFICATION_REQUEST =
             "android.content.pm.verify.domain.extra.VERIFICATION_REQUEST";
 
     /**
      * No response has been recorded by either the system or any verification agent.
+     *
+     * @hide
      */
-    int STATE_NO_RESPONSE = DomainVerificationState.STATE_NO_RESPONSE;
-
-    /** The verification agent has explicitly verified the domain at some point. */
-    int STATE_SUCCESS = DomainVerificationState.STATE_SUCCESS;
+    @SystemApi
+    public static final int STATE_NO_RESPONSE = DomainVerificationState.STATE_NO_RESPONSE;
 
     /**
-     * The first available custom response code. This and any greater integer, along with
-     * {@link #STATE_SUCCESS} are the only values settable by the verification agent. All values
-     * will be treated as if the domain is unverified.
+     * The verification agent has explicitly verified the domain at some point.
+     *
+     * @hide
      */
-    int STATE_FIRST_VERIFIER_DEFINED = DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
+    @SystemApi
+    public static final int STATE_SUCCESS = DomainVerificationState.STATE_SUCCESS;
 
-    /** @hide */
+    /**
+     * The first available custom response code. This and any greater integer, along with {@link
+     * #STATE_SUCCESS} are the only values settable by the verification agent. All values will be
+     * treated as if the domain is unverified.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int STATE_FIRST_VERIFIER_DEFINED =
+            DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
+
+    /**
+     * @hide
+     */
     @NonNull
-    static String stateToDebugString(@DomainVerificationState.State int state) {
+    public static String stateToDebugString(@DomainVerificationState.State int state) {
         switch (state) {
             case DomainVerificationState.STATE_NO_RESPONSE:
                 return "none";
@@ -104,10 +114,13 @@
     }
 
     /**
-     * Checks if a state considers the corresponding domain to be successfully verified. The
-     * domain verification agent may use this to determine whether or not to re-verify a domain.
+     * Checks if a state considers the corresponding domain to be successfully verified. The domain
+     * verification agent may use this to determine whether or not to re-verify a domain.
+     *
+     * @hide
      */
-    static boolean isStateVerified(@DomainVerificationState.State int state) {
+    @SystemApi
+    public static boolean isStateVerified(@DomainVerificationState.State int state) {
         switch (state) {
             case DomainVerificationState.STATE_SUCCESS:
             case DomainVerificationState.STATE_APPROVED:
@@ -126,10 +139,13 @@
     /**
      * Checks if a state is modifiable by the domain verification agent. This is useful as the
      * platform may add new state codes in newer versions, and older verification agents can use
-     * this method to determine if a state can be changed without having to be aware of what the
-     * new state means.
+     * this method to determine if a state can be changed without having to be aware of what the new
+     * state means.
+     *
+     * @hide
      */
-    static boolean isStateModifiable(@DomainVerificationState.State int state) {
+    @SystemApi
+    public static boolean isStateModifiable(@DomainVerificationState.State int state) {
         switch (state) {
             case DomainVerificationState.STATE_NO_RESPONSE:
             case DomainVerificationState.STATE_SUCCESS:
@@ -147,11 +163,12 @@
     }
 
     /**
-     * For determine re-verify policy. This is hidden from the domain verification agent so that
-     * no behavior is made based on the result.
+     * For determine re-verify policy. This is hidden from the domain verification agent so that no
+     * behavior is made based on the result.
+     *
      * @hide
      */
-    static boolean isStateDefault(@DomainVerificationState.State int state) {
+    public static boolean isStateDefault(@DomainVerificationState.State int state) {
         switch (state) {
             case DomainVerificationState.STATE_NO_RESPONSE:
             case DomainVerificationState.STATE_MIGRATED:
@@ -168,14 +185,72 @@
     }
 
     /**
+     * @hide
+     */
+    public static final int ERROR_INVALID_DOMAIN_SET = 1;
+    /**
+     * @hide
+     */
+    public static final int ERROR_NAME_NOT_FOUND = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = {"ERROR_"}, value = {
+            ERROR_INVALID_DOMAIN_SET,
+            ERROR_NAME_NOT_FOUND,
+    })
+    private @interface Error {
+    }
+
+    private final Context mContext;
+
+    private final IDomainVerificationManager mDomainVerificationManager;
+
+
+    /**
+     * System service to access the domain verification APIs.
+     * <p>
+     * Allows the approved domain verification agent on the device (the sole holder of {@link
+     * android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}) to update the approval status of
+     * domains declared by applications in their AndroidManifest.xml, to allow them to open those
+     * links inside the app when selected by the user. This is done through querying {@link
+     * #getDomainVerificationInfo(String)} and calling {@link #setDomainVerificationStatus(UUID,
+     * Set, int)}.
+     * <p>
+     * Also allows the domain preference settings (holder of
+     * {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION})
+     * to update the preferences of the user, when they have chosen to explicitly allow an
+     * application to open links. This is done through querying
+     * {@link #getDomainVerificationUserState(String)} and calling
+     * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)} and
+     * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
+     *
+     * @hide
+     */
+    public DomainVerificationManager(Context context,
+            IDomainVerificationManager domainVerificationManager) {
+        mContext = context;
+        mDomainVerificationManager = domainVerificationManager;
+    }
+
+    /**
      * Used to iterate all {@link DomainVerificationInfo} values to do cleanup or retries. This is
      * usually a heavy workload and should be done infrequently.
      *
      * @return the current snapshot of package names with valid autoVerify URLs.
+     * @hide
      */
+    @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
-    List<String> getValidVerificationPackageNames();
+    public List<String> queryValidVerificationPackageNames() {
+        try {
+            return mDomainVerificationManager.queryValidVerificationPackageNames();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
      * Retrieves the domain verification state for a given package.
@@ -183,61 +258,106 @@
      * @return the data for the package, or null if it does not declare any autoVerify domains
      * @throws NameNotFoundException If the package is unavailable. This is an unrecoverable error
      *                               and should not be re-tried except on a time scheduled basis.
+     * @hide
      */
+    @SystemApi
     @Nullable
     @RequiresPermission(anyOf = {
             android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
             android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
     })
-    DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
-            throws NameNotFoundException;
+    public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
+            throws NameNotFoundException {
+        try {
+            return mDomainVerificationManager.getDomainVerificationInfo(packageName);
+        } catch (Exception e) {
+            Exception converted = rethrow(e, packageName);
+            if (converted instanceof NameNotFoundException) {
+                throw (NameNotFoundException) converted;
+            } else if (converted instanceof RuntimeException) {
+                throw (RuntimeException) converted;
+            } else {
+                throw new RuntimeException(converted);
+            }
+        }
+    }
 
     /**
-     * Change the verification status of the {@param domains} of the package associated with
-     * {@param domainSetId}.
+     * Change the verification status of the {@param domains} of the package associated with {@param
+     * domainSetId}.
      *
      * @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
      * @param domains     List of host names to change the state of.
      * @param state       See {@link DomainVerificationInfo#getHostToStateMap()}.
      * @throws IllegalArgumentException If the ID is invalidated or the {@param domains} are
      *                                  invalid. This usually means the work being processed by the
-     *                                  verification agent is outdated and a new request should
-     *                                  be scheduled, if one has not already been done as part of
-     *                                  the {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION}
-     *                                  broadcast.
+     *                                  verification agent is outdated and a new request should be
+     *                                  scheduled, if one has not already been done as part of the
+     *                                  {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION} broadcast.
      * @throws NameNotFoundException    If the ID is known to be good, but the package is
-     *                                  unavailable. This may be because the package is
-     *                                  installed on a volume that is no longer mounted. This
-     *                                  error is unrecoverable until the package is available
-     *                                  again, and should not be re-tried except on a time
-     *                                  scheduled basis.
+     *                                  unavailable. This may be because the package is installed on
+     *                                  a volume that is no longer mounted. This error is
+     *                                  unrecoverable until the package is available again, and
+     *                                  should not be re-tried except on a time scheduled basis.
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
-    void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
-            @DomainVerificationState.State int state) throws NameNotFoundException;
+    public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
+            @DomainVerificationState.State int state) throws NameNotFoundException {
+        try {
+            mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
+                    new DomainSet(domains), state);
+        } catch (Exception e) {
+            Exception converted = rethrow(e, domainSetId);
+            if (converted instanceof NameNotFoundException) {
+                throw (NameNotFoundException) converted;
+            } else if (converted instanceof RuntimeException) {
+                throw (RuntimeException) converted;
+            } else {
+                throw new RuntimeException(converted);
+            }
+        }
+    }
 
     /**
-     * TODO(b/178525735): This documentation is incorrect in the context of UX changes.
-     * Change whether the given {@param packageName} is allowed to automatically open verified
-     * HTTP/HTTPS domains. The final state is determined along with the verification status for the
-     * specific domain being opened and other system state. An app with this enabled is not
-     * guaranteed to be the sole link handler for its domains.
+     * Change whether the given packageName is allowed to handle BROWSABLE and DEFAULT category web
+     * (HTTP/HTTPS) {@link Intent} Activity open requests. The final state is determined along with
+     * the verification status for the specific domain being opened and other system state. An app
+     * with this enabled is not guaranteed to be the sole link handler for its domains.
+     * <p>
+     * By default, all apps are allowed to open links. Users must disable them explicitly.
      *
-     * By default, all apps are allowed to open verified links. Users must disable them explicitly.
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
-    void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName, boolean allowed)
-            throws NameNotFoundException;
+    public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
+            boolean allowed) throws NameNotFoundException {
+        try {
+            mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(packageName,
+                    allowed, mContext.getUserId());
+        } catch (Exception e) {
+            Exception converted = rethrow(e, packageName);
+            if (converted instanceof NameNotFoundException) {
+                throw (NameNotFoundException) converted;
+            } else if (converted instanceof RuntimeException) {
+                throw (RuntimeException) converted;
+            } else {
+                throw new RuntimeException(converted);
+            }
+        }
+    }
 
     /**
      * Update the recorded user selection for the given {@param domains} for the given {@param
      * domainSetId}. This state is recorded for the lifetime of a domain for a package on device,
      * and will never be reset by the system short of an app data clear.
-     *
+     * <p>
      * This state is stored per device user. If another user needs to be changed, the appropriate
-     * permissions must be acquired and
-     * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
-     *
+     * permissions must be acquired and {@link Context#createContextAsUser(UserHandle, int)} should
+     * be used.
+     * <p>
      * Enabling an unverified domain will allow an application to open it, but this can only occur
      * if no other app on the device is approved for a higher approval level. This can queried
      * using {@link #getOwnersForDomain(String)}.
@@ -255,33 +375,55 @@
      * @throws IllegalArgumentException If the ID is invalidated or the {@param domains} are
      *                                  invalid.
      * @throws NameNotFoundException    If the ID is known to be good, but the package is
-     *                                  unavailable. This may be because the package is
-     *                                  installed on a volume that is no longer mounted. This
-     *                                  error is unrecoverable until the package is available
-     *                                  again, and should not be re-tried except on a time
-     *                                  scheduled basis.
+     *                                  unavailable. This may be because the package is installed on
+     *                                  a volume that is no longer mounted. This error is
+     *                                  unrecoverable until the package is available again, and
+     *                                  should not be re-tried except on a time scheduled basis.
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
-    void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
-            @NonNull Set<String> domains, boolean enabled) throws NameNotFoundException;
+    public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
+            @NonNull Set<String> domains, boolean enabled) throws NameNotFoundException {
+        try {
+            mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
+                    new DomainSet(domains), enabled, mContext.getUserId());
+        } catch (Exception e) {
+            Exception converted = rethrow(e, domainSetId);
+            if (converted instanceof NameNotFoundException) {
+                throw (NameNotFoundException) converted;
+            } else if (converted instanceof RuntimeException) {
+                throw (RuntimeException) converted;
+            } else {
+                throw new RuntimeException(converted);
+            }
+        }
+    }
 
     /**
      * Retrieve the user selection data for the given {@param packageName} and the current user.
-     * It is the responsibility of the caller to ensure that the
-     * {@link DomainVerificationUserSelection#getIdentifier()} matches any prior API calls.
-     *
-     * This state is stored per device user. If another user needs to be accessed, the appropriate
-     * permissions must be acquired and
-     * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
      *
      * @param packageName The app to query state for.
-     * @return the user selection verification data for the given package for the current user,
-     * or null if the package does not declare any HTTP/HTTPS domains.
+     * @return the user selection verification data for the given package for the current user, or
+     * null if the package does not declare any HTTP/HTTPS domains.
      */
     @Nullable
-    @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
-    DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String packageName)
-            throws NameNotFoundException;
+    public DomainVerificationUserState getDomainVerificationUserState(
+            @NonNull String packageName) throws NameNotFoundException {
+        try {
+            return mDomainVerificationManager.getDomainVerificationUserState(packageName,
+                    mContext.getUserId());
+        } catch (Exception e) {
+            Exception converted = rethrow(e, packageName);
+            if (converted instanceof NameNotFoundException) {
+                throw (NameNotFoundException) converted;
+            } else if (converted instanceof RuntimeException) {
+                throw (RuntimeException) converted;
+            } else {
+                throw new RuntimeException(converted);
+            }
+        }
+    }
 
     /**
      * For the given domain, return all apps which are approved to open it in a
@@ -291,21 +433,65 @@
      *
      * By default the list will be returned ordered from lowest to highest
      * priority.
+     *
+     * @hide
      */
+    @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
-    List<DomainOwner> getOwnersForDomain(@NonNull String domain);
+    public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+        try {
+            return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
+        return rethrow(exception, domainSetId, null);
+    }
+
+    private Exception rethrow(Exception exception, @Nullable String packageName) {
+        return rethrow(exception, null, packageName);
+    }
+
+    private Exception rethrow(Exception exception, @Nullable UUID domainSetId,
+            @Nullable String packageName) {
+        if (exception instanceof ServiceSpecificException) {
+            int packedErrorCode = ((ServiceSpecificException) exception).errorCode;
+            if (packageName == null) {
+                packageName = exception.getMessage();
+            }
+
+            @Error int managerErrorCode = packedErrorCode & 0xFFFF;
+            switch (managerErrorCode) {
+                case ERROR_INVALID_DOMAIN_SET:
+                    int errorSpecificCode = packedErrorCode >> 16;
+                    return new IllegalArgumentException(InvalidDomainSetException.buildMessage(
+                            domainSetId, packageName, errorSpecificCode));
+                case ERROR_NAME_NOT_FOUND:
+                    return new NameNotFoundException(packageName);
+                default:
+                    return exception;
+            }
+        } else if (exception instanceof RemoteException) {
+            return ((RemoteException) exception).rethrowFromSystemServer();
+        } else {
+            return exception;
+        }
+    }
 
     /**
      * Thrown if a {@link DomainVerificationInfo#getIdentifier()}} or an associated set of domains
      * provided by the caller is no longer valid. This may be recoverable, and the caller should
      * re-query the package name associated with the ID using
-     * {@link #getDomainVerificationInfo(String)} in order to check. If that also fails, then the
-     * package is no longer known to the device and thus all pending work for it should be dropped.
+     * {@link #getDomainVerificationInfo(String)}
+     * in order to check. If that also fails, then the package is no longer known to the device and
+     * thus all pending work for it should be dropped.
      *
      * @hide
      */
-    class InvalidDomainSetException extends IllegalArgumentException {
+    public static class InvalidDomainSetException extends IllegalArgumentException {
 
         public static final int REASON_ID_NULL = 1;
         public static final int REASON_ID_INVALID = 2;
@@ -313,7 +499,9 @@
         public static final int REASON_UNKNOWN_DOMAIN = 4;
         public static final int REASON_UNABLE_TO_APPROVE = 5;
 
-        /** @hide */
+        /**
+         * @hide
+         */
         @IntDef({
                 REASON_ID_NULL,
                 REASON_ID_INVALID,
@@ -352,7 +540,9 @@
         @Nullable
         private final String mPackageName;
 
-        /** @hide */
+        /**
+         * @hide
+         */
         public InvalidDomainSetException(@Nullable UUID domainSetId, @Nullable String packageName,
                 @Reason int reason) {
             super(buildMessage(domainSetId, packageName, reason));
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java b/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
deleted file mode 100644
index 8b9865c..0000000
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm.verify.domain;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * @hide
- */
-@SuppressWarnings("RedundantThrows")
-public class DomainVerificationManagerImpl implements DomainVerificationManager {
-
-    public static final int ERROR_INVALID_DOMAIN_SET = 1;
-    public static final int ERROR_NAME_NOT_FOUND = 2;
-
-    @IntDef(prefix = { "ERROR_" }, value = {
-            ERROR_INVALID_DOMAIN_SET,
-            ERROR_NAME_NOT_FOUND,
-    })
-    private @interface Error {
-    }
-
-    private final Context mContext;
-
-    private final IDomainVerificationManager mDomainVerificationManager;
-
-    public DomainVerificationManagerImpl(Context context,
-            IDomainVerificationManager domainVerificationManager) {
-        mContext = context;
-        mDomainVerificationManager = domainVerificationManager;
-    }
-
-    @NonNull
-    @Override
-    public List<String> getValidVerificationPackageNames() {
-        try {
-            return mDomainVerificationManager.getValidVerificationPackageNames();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    @Nullable
-    @Override
-    public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
-            throws NameNotFoundException {
-        try {
-            return mDomainVerificationManager.getDomainVerificationInfo(packageName);
-        } catch (Exception e) {
-            Exception converted = rethrow(e, packageName);
-            if (converted instanceof NameNotFoundException) {
-                throw (NameNotFoundException) converted;
-            } else if (converted instanceof RuntimeException) {
-                throw (RuntimeException) converted;
-            } else {
-                throw new RuntimeException(converted);
-            }
-        }
-    }
-
-    @Override
-    public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
-            int state) throws IllegalArgumentException, NameNotFoundException {
-        try {
-            mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
-                    new DomainSet(domains), state);
-        } catch (Exception e) {
-            Exception converted = rethrow(e, domainSetId);
-            if (converted instanceof NameNotFoundException) {
-                throw (NameNotFoundException) converted;
-            } else if (converted instanceof RuntimeException) {
-                throw (RuntimeException) converted;
-            } else {
-                throw new RuntimeException(converted);
-            }
-        }
-    }
-
-    @Override
-    public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
-            boolean allowed) throws NameNotFoundException {
-        try {
-            mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(packageName,
-                    allowed, mContext.getUserId());
-        } catch (Exception e) {
-            Exception converted = rethrow(e, packageName);
-            if (converted instanceof NameNotFoundException) {
-                throw (NameNotFoundException) converted;
-            } else if (converted instanceof RuntimeException) {
-                throw (RuntimeException) converted;
-            } else {
-                throw new RuntimeException(converted);
-            }
-        }
-    }
-
-    @Override
-    public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
-            @NonNull Set<String> domains, boolean enabled)
-            throws IllegalArgumentException, NameNotFoundException {
-        try {
-            mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
-                    new DomainSet(domains), enabled, mContext.getUserId());
-        } catch (Exception e) {
-            Exception converted = rethrow(e, domainSetId);
-            if (converted instanceof NameNotFoundException) {
-                throw (NameNotFoundException) converted;
-            } else if (converted instanceof RuntimeException) {
-                throw (RuntimeException) converted;
-            } else {
-                throw new RuntimeException(converted);
-            }
-        }
-    }
-
-    @Nullable
-    @Override
-    public DomainVerificationUserSelection getDomainVerificationUserSelection(
-            @NonNull String packageName) throws NameNotFoundException {
-        try {
-            return mDomainVerificationManager.getDomainVerificationUserSelection(packageName,
-                    mContext.getUserId());
-        } catch (Exception e) {
-            Exception converted = rethrow(e, packageName);
-            if (converted instanceof NameNotFoundException) {
-                throw (NameNotFoundException) converted;
-            } else if (converted instanceof RuntimeException) {
-                throw (RuntimeException) converted;
-            } else {
-                throw new RuntimeException(converted);
-            }
-        }
-    }
-
-    @NonNull
-    @Override
-    public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
-        try {
-            return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
-        return rethrow(exception, domainSetId, null);
-    }
-
-    private Exception rethrow(Exception exception, @Nullable String packageName) {
-        return rethrow(exception, null, packageName);
-    }
-
-    private Exception rethrow(Exception exception, @Nullable UUID domainSetId,
-            @Nullable String packageName) {
-        if (exception instanceof ServiceSpecificException) {
-            int packedErrorCode = ((ServiceSpecificException) exception).errorCode;
-            if (packageName == null) {
-                packageName = exception.getMessage();
-            }
-
-            @Error int managerErrorCode = packedErrorCode & 0xFFFF;
-            switch (managerErrorCode) {
-                case ERROR_INVALID_DOMAIN_SET:
-                    int errorSpecificCode = packedErrorCode >> 16;
-                    return new IllegalArgumentException(InvalidDomainSetException.buildMessage(
-                            domainSetId, packageName, errorSpecificCode));
-                case ERROR_NAME_NOT_FOUND:
-                    return new NameNotFoundException(packageName);
-                default:
-                    return exception;
-            }
-        } else if (exception instanceof RemoteException) {
-            return ((RemoteException) exception).rethrowFromSystemServer();
-        } else {
-            return exception;
-        }
-    }
-}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.aidl
similarity index 93%
rename from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
rename to core/java/android/content/pm/verify/domain/DomainVerificationUserState.aidl
index ddb5ef8..94690c1 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.aidl
@@ -16,4 +16,4 @@
 
 package android.content.pm.verify.domain;
 
-parcelable DomainVerificationUserSelection;
+parcelable DomainVerificationUserState;
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
similarity index 82%
rename from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
rename to core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
index d23f5f1..1e60abb 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
@@ -29,39 +30,36 @@
 import com.android.internal.util.Parcelling;
 
 import java.util.Map;
-import java.util.Set;
 import java.util.UUID;
 
 /**
  * Contains the user selection state for a package. This means all web HTTP(S) domains declared by a
  * package in its manifest, whether or not they were marked for auto verification.
  * <p>
- * By default, all apps are allowed to automatically open links with domains that they've
- * successfully verified against. This is reflected by {@link #isLinkHandlingAllowed()}. The user
- * can decide to disable this, disallowing the application from opening all links. Note that the
- * toggle affects <b>all</b> links and is not based on the verification state of the domains.
+ * Applications should use {@link #getHostToStateMap()} if necessary to
+ * check if/how they are verified for a domain, which is required starting from platform
+ * {@link android.os.Build.VERSION_CODES#S} in order to open {@link Intent}s which declare
+ * {@link Intent#CATEGORY_BROWSABLE} or no category and also match against
+ * {@link Intent#CATEGORY_DEFAULT} {@link android.content.IntentFilter}s, either through an
+ * explicit declaration of {@link Intent#CATEGORY_DEFAULT} or through the use of
+ * {@link android.content.pm.PackageManager#MATCH_DEFAULT_ONLY}, which is usually added for the
+ * caller when using {@link Context#startActivity(Intent)} and similar.
+ * <p>
+ * By default, all apps are allowed to automatically open links for the above case for domains that
+ * they've successfully verified against. This is reflected by {@link #isLinkHandlingAllowed()}.
+ * The user can decide to disable this, disallowing the application from opening all links. Note
+ * that the toggle affects <b>all</b> links and is not based on the verification state of the
+ * domains.
  * <p>
  * Assuming the toggle is enabled, the user can also select additional unverified domains to grant
  * to the application to open, which is reflected in {@link #getHostToStateMap()}. But only a single
  * application can be approved for a domain unless the applications are both approved. If another
  * application is approved, the user will not be allowed to enable the domain.
- * <p>
- * These values can be changed through the
- * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
- * boolean)} and {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
- * boolean)} APIs.
- * <p>
- * Note that because state is per user, if a different user needs to be changed, one will need to
- * use {@link Context#createContextAsUser(UserHandle, int)} and hold the {@link
- * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
- *
- * @hide
  */
-@SystemApi
 @SuppressWarnings("DefaultAnnotationParam")
 @DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
         genEqualsHashCode = true, genHiddenConstDefs = true)
-public final class DomainVerificationUserSelection implements Parcelable {
+public final class DomainVerificationUserState implements Parcelable {
 
     /**
      * The domain is unverified and unselected, and the application is unable to open web links
@@ -70,9 +68,8 @@
     public static final int DOMAIN_STATE_NONE = 0;
 
     /**
-     * The domain has been selected through the
-     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)}
-     * API, under the assumption it has not been reset by the system.
+     * The domain has been selected by the user. This may be reset to {@link #DOMAIN_STATE_NONE} if
+     * another application is selected or verified for the same domain.
      */
     public static final int DOMAIN_STATE_SELECTED = 1;
 
@@ -119,7 +116,16 @@
     @NonNull
     private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
         return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
-                DomainVerificationUserSelection.class.getClassLoader());
+                DomainVerificationUserState.class.getClassLoader());
+    }
+
+    /**
+     * @see DomainVerificationInfo#getIdentifier
+     * @hide
+     */
+    @SystemApi
+    public @NonNull UUID getIdentifier() {
+        return mIdentifier;
     }
 
 
@@ -130,7 +136,7 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -162,7 +168,7 @@
     }
 
     /**
-     * Creates a new DomainVerificationUserSelection.
+     * Creates a new DomainVerificationUserState.
      *
      * @param packageName
      *   The package name that this data corresponds to.
@@ -175,7 +181,7 @@
      * @hide
      */
     @DataClass.Generated.Member
-    public DomainVerificationUserSelection(
+    public DomainVerificationUserState(
             @NonNull UUID identifier,
             @NonNull String packageName,
             @NonNull UserHandle user,
@@ -201,14 +207,6 @@
     }
 
     /**
-     * @see DomainVerificationInfo#getIdentifier
-     */
-    @DataClass.Generated.Member
-    public @NonNull UUID getIdentifier() {
-        return mIdentifier;
-    }
-
-    /**
      * The package name that this data corresponds to.
      */
     @DataClass.Generated.Member
@@ -246,7 +244,7 @@
         // You can override field toString logic by defining methods like:
         // String fieldNameToString() { ... }
 
-        return "DomainVerificationUserSelection { " +
+        return "DomainVerificationUserState { " +
                 "identifier = " + mIdentifier + ", " +
                 "packageName = " + mPackageName + ", " +
                 "user = " + mUser + ", " +
@@ -259,13 +257,13 @@
     @DataClass.Generated.Member
     public boolean equals(@Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
-        // boolean fieldNameEquals(DomainVerificationUserSelection other) { ... }
+        // boolean fieldNameEquals(DomainVerificationUserState other) { ... }
         // boolean fieldNameEquals(FieldType otherValue) { ... }
 
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         @SuppressWarnings("unchecked")
-        DomainVerificationUserSelection that = (DomainVerificationUserSelection) o;
+        DomainVerificationUserState that = (DomainVerificationUserState) o;
         //noinspection PointlessBooleanExpression
         return true
                 && java.util.Objects.equals(mIdentifier, that.mIdentifier)
@@ -323,7 +321,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ DomainVerificationUserSelection(@NonNull Parcel in) {
+    /* package-private */ DomainVerificationUserState(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -354,24 +352,24 @@
     }
 
     @DataClass.Generated.Member
-    public static final @NonNull Parcelable.Creator<DomainVerificationUserSelection> CREATOR
-            = new Parcelable.Creator<DomainVerificationUserSelection>() {
+    public static final @NonNull Parcelable.Creator<DomainVerificationUserState> CREATOR
+            = new Parcelable.Creator<DomainVerificationUserState>() {
         @Override
-        public DomainVerificationUserSelection[] newArray(int size) {
-            return new DomainVerificationUserSelection[size];
+        public DomainVerificationUserState[] newArray(int size) {
+            return new DomainVerificationUserState[size];
         }
 
         @Override
-        public DomainVerificationUserSelection createFromParcel(@NonNull Parcel in) {
-            return new DomainVerificationUserSelection(in);
+        public DomainVerificationUserState createFromParcel(@NonNull Parcel in) {
+            return new DomainVerificationUserState(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1613683603297L,
+            time = 1614721840152L,
             codegenVersion = "1.0.22",
-            sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
-            inputSignatures = "public static final  int DOMAIN_STATE_NONE\npublic static final  int DOMAIN_STATE_SELECTED\npublic static final  int DOMAIN_STATE_VERIFIED\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate  void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
+            sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java",
+            inputSignatures = "public static final  int DOMAIN_STATE_NONE\npublic static final  int DOMAIN_STATE_SELECTED\npublic static final  int DOMAIN_STATE_VERIFIED\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate  void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\npublic @android.annotation.SystemApi @android.annotation.NonNull java.util.UUID getIdentifier()\nclass DomainVerificationUserState extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
index 701af32..332b925 100644
--- a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
+++ b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
@@ -19,7 +19,7 @@
 import android.content.pm.verify.domain.DomainOwner;
 import android.content.pm.verify.domain.DomainSet;
 import android.content.pm.verify.domain.DomainVerificationInfo;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
 import java.util.List;
 
 /**
@@ -28,13 +28,13 @@
  */
 interface IDomainVerificationManager {
 
-    List<String> getValidVerificationPackageNames();
+    List<String> queryValidVerificationPackageNames();
 
     @nullable
     DomainVerificationInfo getDomainVerificationInfo(String packageName);
 
     @nullable
-    DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
+    DomainVerificationUserState getDomainVerificationUserState(String packageName,
             int userId);
 
     @nullable
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index 2d381eb..de48ed7 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -22,6 +22,7 @@
 import android.content.om.OverlayableInfo;
 import android.content.res.loader.AssetsProvider;
 import android.content.res.loader.ResourcesProvider;
+import android.text.TextUtils;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -344,7 +345,14 @@
     @UnsupportedAppUsage
     public @NonNull String getAssetPath() {
         synchronized (this) {
-            return nativeGetAssetPath(mNativePtr);
+            return TextUtils.emptyIfNull(nativeGetAssetPath(mNativePtr));
+        }
+    }
+
+    /** @hide */
+    public @NonNull String getDebugName() {
+        synchronized (this) {
+            return nativeGetDebugName(mNativePtr);
         }
     }
 
@@ -422,7 +430,7 @@
 
     @Override
     public String toString() {
-        return "ApkAssets{path=" + getAssetPath() + "}";
+        return "ApkAssets{path=" + getDebugName() + "}";
     }
 
     /**
@@ -450,6 +458,7 @@
             @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length,
             @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
     private static native @NonNull String nativeGetAssetPath(long ptr);
+    private static native @NonNull String nativeGetDebugName(long ptr);
     private static native long nativeGetStringBlock(long ptr);
     private static native boolean nativeIsUpToDate(long ptr);
     private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index fd98d37..31d1b69 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -62,10 +62,13 @@
      * @hide
      */
     int TYPE_FACE = 1 << 3;
-    @IntDef({TYPE_NONE,
+
+    @IntDef(flag = true, value = {
+            TYPE_NONE,
             TYPE_CREDENTIAL,
             TYPE_FINGERPRINT,
-            TYPE_IRIS})
+            TYPE_IRIS
+    })
     @Retention(RetentionPolicy.SOURCE)
     @interface Modality {}
 
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 5b28e00..1fdce5e 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -23,6 +23,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -193,15 +194,15 @@
         int DEVICE_CREDENTIAL = 1 << 15;
     }
 
-    private final Context mContext;
-    private final IAuthService mService;
+    @NonNull private final Context mContext;
+    @NonNull private final IAuthService mService;
 
     /**
      * @hide
      * @param context
      * @param service
      */
-    public BiometricManager(Context context, IAuthService service) {
+    public BiometricManager(@NonNull Context context, @NonNull IAuthService service) {
         mContext = context;
         mService = service;
     }
@@ -274,7 +275,8 @@
      */
     @Deprecated
     @RequiresPermission(USE_BIOMETRIC)
-    public @BiometricError int canAuthenticate() {
+    @BiometricError
+    public int canAuthenticate() {
         return canAuthenticate(Authenticators.BIOMETRIC_WEAK);
     }
 
@@ -304,7 +306,8 @@
      *     authenticators can currently be used (enrolled and available).
      */
     @RequiresPermission(USE_BIOMETRIC)
-    public @BiometricError int canAuthenticate(@Authenticators.Types int authenticators) {
+    @BiometricError
+    public int canAuthenticate(@Authenticators.Types int authenticators) {
         return canAuthenticate(mContext.getUserId(), authenticators);
     }
 
@@ -312,8 +315,10 @@
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
-    public @BiometricError int canAuthenticate(int userId,
-            @Authenticators.Types int authenticators) {
+    @BiometricError
+    public int canAuthenticate(
+            int userId, @Authenticators.Types int authenticators) {
+
         if (mService != null) {
             try {
                 final String opPackageName = mContext.getOpPackageName();
@@ -322,7 +327,7 @@
                 throw e.rethrowFromSystemServer();
             }
         } else {
-            Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
+            Slog.w(TAG, "canAuthenticate(): Service not connected");
             return BIOMETRIC_ERROR_HW_UNAVAILABLE;
         }
     }
@@ -404,5 +409,115 @@
         }
     }
 
+    /**
+     * Provides a localized string that may be used as the label for a button that invokes
+     * {@link BiometricPrompt}.
+     *
+     * <p>When possible, this method should use the given authenticator requirements to more
+     * precisely specify the authentication type that will be used. For example, if
+     * <strong>Class 3</strong> biometric authentication is requested on a device with a
+     * <strong>Class 3</strong> fingerprint sensor and a <strong>Class 2</strong> face sensor, the
+     * returned string should indicate that fingerprint authentication will be used.
+     *
+     * <p>This method should also try to specify which authentication method(s) will be used in
+     * practice when multiple authenticators meet the given requirements. For example, if biometric
+     * authentication is requested on a device with both face and fingerprint sensors but the user
+     * has selected face as their preferred method, the returned string should indicate that face
+     * authentication will be used.
+     *
+     * @param authenticators A bit field representing the types of {@link Authenticators} that may
+     *                       be used for authentication.
+     * @return The label for a button that invokes {@link BiometricPrompt} for authentication.
+     */
+    @RequiresPermission(USE_BIOMETRIC)
+    @Nullable
+    public CharSequence getButtonLabel(@Authenticators.Types int authenticators) {
+        if (mService != null) {
+            final int userId = mContext.getUserId();
+            final String opPackageName = mContext.getOpPackageName();
+            try {
+                return mService.getButtonLabel(userId, opPackageName, authenticators);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "getButtonLabel(): Service not connected");
+            return null;
+        }
+    }
+
+    /**
+     * Provides a localized string that may be shown while the user is authenticating with
+     * {@link BiometricPrompt}.
+     *
+     * <p>When possible, this method should use the given authenticator requirements to more
+     * precisely specify the authentication type that will be used. For example, if
+     * <strong>Class 3</strong> biometric authentication is requested on a device with a
+     * <strong>Class 3</strong> fingerprint sensor and a <strong>Class 2</strong> face sensor, the
+     * returned string should indicate that fingerprint authentication will be used.
+     *
+     * <p>This method should also try to specify which authentication method(s) will be used in
+     * practice when multiple authenticators meet the given requirements. For example, if biometric
+     * authentication is requested on a device with both face and fingerprint sensors but the user
+     * has selected face as their preferred method, the returned string should indicate that face
+     * authentication will be used.
+     *
+     * @param authenticators A bit field representing the types of {@link Authenticators} that may
+     *                       be used for authentication.
+     * @return The label for a button that invokes {@link BiometricPrompt} for authentication.
+     */
+    @RequiresPermission(USE_BIOMETRIC)
+    @Nullable
+    public CharSequence getPromptMessage(@Authenticators.Types int authenticators) {
+        if (mService != null) {
+            final int userId = mContext.getUserId();
+            final String opPackageName = mContext.getOpPackageName();
+            try {
+                return mService.getPromptMessage(userId, opPackageName, authenticators);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "getPromptMessage(): Service not connected");
+            return null;
+        }
+    }
+
+    /**
+     * Provides a localized string that may be shown as the title for an app setting that enables
+     * biometric authentication.
+     *
+     * <p>When possible, this method should use the given authenticator requirements to more
+     * precisely specify the authentication type that will be used. For example, if
+     * <strong>Class 3</strong> biometric authentication is requested on a device with a
+     * <strong>Class 3</strong> fingerprint sensor and a <strong>Class 2</strong> face sensor, the
+     * returned string should indicate that fingerprint authentication will be used.
+     *
+     * <p>This method should <em>not</em> try to specify which authentication method(s) will be used
+     * in practice when multiple authenticators meet the given requirements. For example, if
+     * biometric authentication is requested on a device with both face and fingerprint sensors, the
+     * returned string should indicate that either face or fingerprint authentication may be used,
+     * regardless of whether the user has enrolled or selected either as their preferred method.
+     *
+     * @param authenticators A bit field representing the types of {@link Authenticators} that may
+     *                       be used for authentication.
+     * @return The label for a button that invokes {@link BiometricPrompt} for authentication.
+     */
+    @RequiresPermission(USE_BIOMETRIC)
+    @Nullable
+    public CharSequence getSettingName(@Authenticators.Types int authenticators) {
+        if (mService != null) {
+            final int userId = mContext.getUserId();
+            final String opPackageName = mContext.getOpPackageName();
+            try {
+                return mService.getSettingName(userId, opPackageName, authenticators);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "getSettingName(): Service not connected");
+            return null;
+        }
+    }
 }
 
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index d8c9dbc..1472bb9 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -68,4 +68,16 @@
     // the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
     // land as SIDs, and are used during key generation.
     long[] getAuthenticatorIds();
+
+    // Provides a localized string that may be used as the label for a button that invokes
+    // BiometricPrompt.
+    CharSequence getButtonLabel(int userId, String opPackageName, int authenticators);
+
+    // Provides a localized string that may be shown while the user is authenticating with
+    // BiometricPrompt.
+    CharSequence getPromptMessage(int userId, String opPackageName, int authenticators);
+
+    // Provides a localized string that may be shown as the title for an app setting that enables
+    // biometric authentication.
+    CharSequence getSettingName(int userId, String opPackageName, int authenticators);
 }
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 2433186..6d8bf0f 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -75,4 +75,10 @@
     long[] getAuthenticatorIds(int callingUserId);
 
     int getCurrentStrength(int sensorId);
+
+    // Returns a bit field of the modality (or modalities) that are will be used for authentication.
+    int getCurrentModality(String opPackageName, int userId, int callingUserId, int authenticators);
+
+    // Returns a bit field of the authentication modalities that are supported by this device.
+    int getSupportedModalities(int authenticators);
 }
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
similarity index 79%
copy from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
copy to core/java/android/hardware/devicestate/DeviceStateInfo.aidl
index ddb5ef8..e856792 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.content.pm.verify.domain;
+package android.hardware.devicestate;
 
-parcelable DomainVerificationUserSelection;
+parcelable DeviceStateInfo;
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.java b/core/java/android/hardware/devicestate/DeviceStateInfo.java
new file mode 100644
index 0000000..bc6af37
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.devicestate;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+
+/**
+ * Information about the state of the device.
+ *
+ * @hide
+ */
+public final class DeviceStateInfo implements Parcelable {
+    /** Bit that indicates the {@link #supportedStates} field has changed. */
+    public static final int CHANGED_SUPPORTED_STATES = 1 << 0;
+
+    /** Bit that indicates the {@link #baseState} field has changed. */
+    public static final int CHANGED_BASE_STATE = 1 << 1;
+
+    /** Bit that indicates the {@link #currentState} field has changed. */
+    public static final int CHANGED_CURRENT_STATE = 1 << 2;
+
+    @IntDef(prefix = {"CHANGED_"}, flag = true, value = {
+            CHANGED_SUPPORTED_STATES,
+            CHANGED_BASE_STATE,
+            CHANGED_CURRENT_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ChangeFlags {}
+
+    /**
+     * The list of states supported by the device.
+     */
+    @NonNull
+    public final int[] supportedStates;
+
+    /**
+     * The base (non-override) state of the device. The base state is the state of the device
+     * ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
+     * DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+     */
+    public final int baseState;
+
+    /**
+     * The state of the device.
+     */
+    public final int currentState;
+
+    /**
+     * Creates a new instance of {@link DeviceStateInfo}.
+     * <p>
+     * NOTE: Unlike {@link #DeviceStateInfo(DeviceStateInfo)}, this constructor does not copy the
+     * supplied parameters.
+     */
+    public DeviceStateInfo(@NonNull int[] supportedStates, int baseState, int state) {
+        this.supportedStates = supportedStates;
+        this.baseState = baseState;
+        this.currentState = state;
+    }
+
+    /**
+     * Creates a new instance of {@link DeviceStateInfo} copying the fields of {@code info} into
+     * the fields of the returned instance.
+     */
+    public DeviceStateInfo(@NonNull DeviceStateInfo info) {
+        this(Arrays.copyOf(info.supportedStates, info.supportedStates.length),
+                info.baseState, info.currentState);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (this == other) return true;
+        if (other == null || getClass() != other.getClass()) return false;
+        DeviceStateInfo that = (DeviceStateInfo) other;
+        return baseState == that.baseState
+                &&  currentState == that.currentState
+                && Arrays.equals(supportedStates, that.supportedStates);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(baseState, currentState);
+        result = 31 * result + Arrays.hashCode(supportedStates);
+        return result;
+    }
+
+    /** Returns a bitmask of the differences between this instance and {@code other}. */
+    @ChangeFlags
+    public int diff(@NonNull DeviceStateInfo other) {
+        int diff = 0;
+        if (!Arrays.equals(supportedStates, other.supportedStates)) {
+            diff |= CHANGED_SUPPORTED_STATES;
+        }
+        if (baseState != other.baseState) {
+            diff |= CHANGED_BASE_STATE;
+        }
+        if (currentState != other.currentState) {
+            diff |= CHANGED_CURRENT_STATE;
+        }
+        return diff;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(supportedStates.length);
+        for (int i = 0; i < supportedStates.length; i++) {
+            dest.writeInt(supportedStates[i]);
+        }
+
+        dest.writeInt(baseState);
+        dest.writeInt(currentState);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<DeviceStateInfo>() {
+        @Override
+        public DeviceStateInfo createFromParcel(Parcel source) {
+            final int numberOfSupportedStates = source.readInt();
+            final int[] supportedStates = new int[numberOfSupportedStates];
+            for (int i = 0; i < numberOfSupportedStates; i++) {
+                supportedStates[i] = source.readInt();
+            }
+            final int baseState = source.readInt();
+            final int currentState = source.readInt();
+
+            return new DeviceStateInfo(supportedStates, baseState, currentState);
+        }
+
+        @Override
+        public DeviceStateInfo[] newArray(int size) {
+            return new DeviceStateInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 2d4b2cc..250145e 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -111,38 +111,63 @@
     }
 
     /**
-     * Registers a listener to receive notifications about changes in device state.
+     * Registers a callback to receive notifications about changes in device state.
      *
      * @param executor the executor to process notifications.
-     * @param listener the listener to register.
+     * @param callback the callback to register.
      *
-     * @see DeviceStateListener
+     * @see DeviceStateCallback
      */
-    public void addDeviceStateListener(@NonNull @CallbackExecutor Executor executor,
-            @NonNull DeviceStateListener listener) {
-        mGlobal.registerDeviceStateListener(listener, executor);
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull DeviceStateCallback callback) {
+        mGlobal.registerDeviceStateCallback(callback, executor);
     }
 
     /**
-     * Unregisters a listener previously registered with
-     * {@link #addDeviceStateListener(Executor, DeviceStateListener)}.
+     * Unregisters a callback previously registered with
+     * {@link #registerCallback(Executor, DeviceStateCallback)}.
      */
-    public void removeDeviceStateListener(@NonNull DeviceStateListener listener) {
-        mGlobal.unregisterDeviceStateListener(listener);
+    public void unregisterCallback(@NonNull DeviceStateCallback callback) {
+        mGlobal.unregisterDeviceStateCallback(callback);
     }
 
-    /**
-     * Listens for changes in device states.
-     */
-    public interface DeviceStateListener {
+    /** Callback to receive notifications about changes in device state. */
+    public interface DeviceStateCallback {
+        /**
+         * Called in response to a change in the states supported by the device.
+         * <p>
+         * Guaranteed to be called once on registration of the callback with the initial value and
+         * then on every subsequent change in the supported states.
+         *
+         * @param supportedStates the new supported states.
+         *
+         * @see DeviceStateManager#getSupportedStates()
+         */
+        default void onSupportedStatesChanged(@NonNull int[] supportedStates) {}
+
+        /**
+         * Called in response to a change in the base device state.
+         * <p>
+         * The base state is the state of the device without considering any requests made through
+         * calls to {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}
+         * from any client process. The base state is guaranteed to match the state provided with a
+         * call to {@link #onStateChanged(int)} when there are no active requests from any process.
+         * <p>
+         * Guaranteed to be called once on registration of the callback with the initial value and
+         * then on every subsequent change in the non-override state.
+         *
+         * @param state the new base device state.
+         */
+        default void onBaseStateChanged(int state) {}
+
         /**
          * Called in response to device state changes.
          * <p>
-         * Guaranteed to be called once on registration of the listener with the
-         * initial value and then on every subsequent change in device state.
+         * Guaranteed to be called once on registration of the callback with the initial value and
+         * then on every subsequent change in device state.
          *
-         * @param deviceState the new device state.
+         * @param state the new device state.
          */
-        void onDeviceStateChanged(int deviceState);
+        void onStateChanged(int state);
     }
 }
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index b9ae88e..1b37fb9 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.hardware.devicestate.DeviceStateManager.DeviceStateListener;
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,12 +31,14 @@
 import com.android.internal.annotations.VisibleForTesting.Visibility;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.concurrent.Executor;
 
 /**
  * Provides communication with the device state system service on behalf of applications.
  *
  * @see DeviceStateManager
+ *
  * @hide
  */
 @VisibleForTesting(visibility = Visibility.PACKAGE)
@@ -68,13 +70,13 @@
     private DeviceStateManagerCallback mCallback;
 
     @GuardedBy("mLock")
-    private final ArrayList<DeviceStateListenerWrapper> mListeners = new ArrayList<>();
+    private final ArrayList<DeviceStateCallbackWrapper> mCallbacks = new ArrayList<>();
     @GuardedBy("mLock")
     private final ArrayMap<IBinder, DeviceStateRequestWrapper> mRequests = new ArrayMap<>();
 
     @Nullable
     @GuardedBy("mLock")
-    private Integer mLastReceivedState;
+    private DeviceStateInfo mLastReceivedInfo;
 
     @VisibleForTesting
     public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
@@ -87,18 +89,31 @@
      * @see DeviceStateManager#getSupportedStates()
      */
     public int[] getSupportedStates() {
-        try {
-            return mDeviceStateManager.getSupportedDeviceStates();
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
+        synchronized (mLock) {
+            final DeviceStateInfo currentInfo;
+            if (mLastReceivedInfo != null) {
+                // If we have mLastReceivedInfo a callback is registered for this instance and it
+                // is receiving the most recent info from the server. Use that info here.
+                currentInfo = mLastReceivedInfo;
+            } else {
+                // If mLastReceivedInfo is null there is no registered callback so we manually
+                // fetch the current info.
+                try {
+                    currentInfo = mDeviceStateManager.getDeviceStateInfo();
+                } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
+                }
+            }
+
+            return Arrays.copyOf(currentInfo.supportedStates, currentInfo.supportedStates.length);
         }
     }
 
     /**
      * Submits a {@link DeviceStateRequest request} to modify the device state.
      *
-     * @see DeviceStateManager#requestState(DeviceStateRequest,
-     * Executor, DeviceStateRequest.Callback)
+     * @see DeviceStateManager#requestState(DeviceStateRequest, Executor,
+     * DeviceStateRequest.Callback)
      * @see DeviceStateRequest
      */
     public void requestState(@NonNull DeviceStateRequest request,
@@ -157,49 +172,56 @@
     }
 
     /**
-     * Registers a listener to receive notifications about changes in device state.
+     * Registers a callback to receive notifications about changes in device state.
      *
-     * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+     * @see DeviceStateManager#registerCallback(Executor, DeviceStateCallback)
      */
     @VisibleForTesting(visibility = Visibility.PACKAGE)
-    public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
+    public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
             @NonNull Executor executor) {
-        Integer stateToReport;
-        DeviceStateListenerWrapper wrapper;
+        DeviceStateCallbackWrapper wrapper;
+        DeviceStateInfo currentInfo;
         synchronized (mLock) {
-            registerCallbackIfNeededLocked();
-
-            int index = findListenerLocked(listener);
+            int index = findCallbackLocked(callback);
             if (index != -1) {
-                // This listener is already registered.
+                // This callback is already registered.
                 return;
             }
 
-            wrapper = new DeviceStateListenerWrapper(listener, executor);
-            mListeners.add(wrapper);
-            stateToReport = mLastReceivedState;
+            registerCallbackIfNeededLocked();
+            if (mLastReceivedInfo == null) {
+                // Initialize the last received info with the current info if this is the first
+                // callback being registered.
+                try {
+                    mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo();
+                } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
+                }
+            }
+
+            currentInfo = new DeviceStateInfo(mLastReceivedInfo);
+
+            wrapper = new DeviceStateCallbackWrapper(callback, executor);
+            mCallbacks.add(wrapper);
         }
 
-        if (stateToReport != null) {
-            // Notify the listener with the most recent device state from the server. If the state
-            // to report is null this is likely the first listener added and we're still waiting
-            // from the callback from the server.
-            wrapper.notifyDeviceStateChanged(stateToReport);
-        }
+        wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
+        wrapper.notifyBaseStateChanged(currentInfo.baseState);
+        wrapper.notifyStateChanged(currentInfo.currentState);
     }
 
     /**
-     * Unregisters a listener previously registered with
-     * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+     * Unregisters a callback previously registered with
+     * {@link #registerDeviceStateCallback(DeviceStateCallback, Executor)}}.
      *
-     * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+     * @see DeviceStateManager#unregisterCallback(DeviceStateCallback)
      */
     @VisibleForTesting(visibility = Visibility.PACKAGE)
-    public void unregisterDeviceStateListener(DeviceStateListener listener) {
+    public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
         synchronized (mLock) {
-            int indexToRemove = findListenerLocked(listener);
+            int indexToRemove = findCallbackLocked(callback);
             if (indexToRemove != -1) {
-                mListeners.remove(indexToRemove);
+                mCallbacks.remove(indexToRemove);
             }
         }
     }
@@ -210,14 +232,15 @@
             try {
                 mDeviceStateManager.registerCallback(mCallback);
             } catch (RemoteException ex) {
+                mCallback = null;
                 throw ex.rethrowFromSystemServer();
             }
         }
     }
 
-    private int findListenerLocked(DeviceStateListener listener) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            if (mListeners.get(i).mDeviceStateListener.equals(listener)) {
+    private int findCallbackLocked(DeviceStateCallback callback) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            if (mCallbacks.get(i).mDeviceStateCallback.equals(callback)) {
                 return i;
             }
         }
@@ -234,16 +257,34 @@
         return null;
     }
 
-    /** Handles a call from the server that the device state has changed. */
-    private void handleDeviceStateChanged(int newDeviceState) {
-        ArrayList<DeviceStateListenerWrapper> listeners;
+    /** Handles a call from the server that the device state info has changed. */
+    private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
+        ArrayList<DeviceStateCallbackWrapper> callbacks;
+        DeviceStateInfo oldInfo;
         synchronized (mLock) {
-            mLastReceivedState = newDeviceState;
-            listeners = new ArrayList<>(mListeners);
+            oldInfo = mLastReceivedInfo;
+            mLastReceivedInfo = info;
+            callbacks = new ArrayList<>(mCallbacks);
         }
 
-        for (int i = 0; i < listeners.size(); i++) {
-            listeners.get(i).notifyDeviceStateChanged(newDeviceState);
+        final int diff = oldInfo == null ? 1 : info.diff(oldInfo);
+        if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
+            for (int i = 0; i < callbacks.size(); i++) {
+                // Copy the array to prevent callbacks from modifying the internal state.
+                final int[] supportedStates = Arrays.copyOf(info.supportedStates,
+                        info.supportedStates.length);
+                callbacks.get(i).notifySupportedStatesChanged(supportedStates);
+            }
+        }
+        if ((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0) {
+            for (int i = 0; i < callbacks.size(); i++) {
+                callbacks.get(i).notifyBaseStateChanged(info.baseState);
+            }
+        }
+        if ((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0) {
+            for (int i = 0; i < callbacks.size(); i++) {
+                callbacks.get(i).notifyStateChanged(info.currentState);
+            }
         }
     }
 
@@ -291,8 +332,8 @@
 
     private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
         @Override
-        public void onDeviceStateChanged(int deviceState) {
-            handleDeviceStateChanged(deviceState);
+        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+            handleDeviceStateInfoChanged(info);
         }
 
         @Override
@@ -311,17 +352,29 @@
         }
     }
 
-    private static final class DeviceStateListenerWrapper {
-        private final DeviceStateListener mDeviceStateListener;
+    private static final class DeviceStateCallbackWrapper {
+        @NonNull
+        private final DeviceStateCallback mDeviceStateCallback;
+        @NonNull
         private final Executor mExecutor;
 
-        DeviceStateListenerWrapper(DeviceStateListener listener, Executor executor) {
-            mDeviceStateListener = listener;
+        DeviceStateCallbackWrapper(@NonNull DeviceStateCallback callback,
+                @NonNull Executor executor) {
+            mDeviceStateCallback = callback;
             mExecutor = executor;
         }
 
-        void notifyDeviceStateChanged(int newDeviceState) {
-            mExecutor.execute(() -> mDeviceStateListener.onDeviceStateChanged(newDeviceState));
+        void notifySupportedStatesChanged(int[] newSupportedStates) {
+            mExecutor.execute(() ->
+                    mDeviceStateCallback.onSupportedStatesChanged(newSupportedStates));
+        }
+
+        void notifyBaseStateChanged(int newBaseState) {
+            mExecutor.execute(() -> mDeviceStateCallback.onBaseStateChanged(newBaseState));
+        }
+
+        void notifyStateChanged(int newDeviceState) {
+            mExecutor.execute(() -> mDeviceStateCallback.onStateChanged(newDeviceState));
         }
     }
 
diff --git a/core/java/android/hardware/devicestate/DeviceStateRequest.java b/core/java/android/hardware/devicestate/DeviceStateRequest.java
index 70f7002..df488d2 100644
--- a/core/java/android/hardware/devicestate/DeviceStateRequest.java
+++ b/core/java/android/hardware/devicestate/DeviceStateRequest.java
@@ -116,7 +116,7 @@
          * requested state.
          * <p>
          * Guaranteed to be called after a call to
-         * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)} with a state
+         * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} with a state
          * matching the requested state.
          */
         default void onRequestActivated(@NonNull DeviceStateRequest request) {}
@@ -125,7 +125,7 @@
          * Called to indicate the request has been temporarily suspended.
          * <p>
          * Guaranteed to be called before a call to
-         * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+         * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
          */
         default void onRequestSuspended(@NonNull DeviceStateRequest request) {}
 
@@ -135,7 +135,7 @@
          * DeviceStateRequest.Callback)}.
          * <p>
          * Guaranteed to be called before a call to
-         * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+         * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
          * <p>
          * Note: A call to {@link #onRequestSuspended(DeviceStateRequest)} is not guaranteed to
          * occur before this method.
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index 323ad21..14ed03d 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -16,25 +16,26 @@
 
 package android.hardware.devicestate;
 
+import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
 
 /** @hide */
 interface IDeviceStateManager {
+    /** Returns the current device state info. */
+    DeviceStateInfo getDeviceStateInfo();
+
     /**
      * Registers a callback to receive notifications from the device state manager. Only one
      * callback can be registered per-process.
      * <p>
      * As the callback mechanism is used to alert the caller of changes to request status a callback
      * <b>MUST</b> be registered before calling {@link #requestState(IBinder, int, int)} or
-     * {@link #cancelRequest(IBinder)}. Otherwise an exception will be thrown.
+     * {@link #cancelRequest(IBinder)}, otherwise an exception will be thrown.
      *
      * @throws SecurityException if a callback is already registered for the calling process.
      */
     void registerCallback(in IDeviceStateManagerCallback callback);
 
-    /** Returns the array of supported device state identifiers. */
-    int[] getSupportedDeviceStates();
-
     /**
      * Requests that the device enter the supplied {@code state}. A callback <b>MUST</b> have been
      * previously registered with {@link #registerCallback(IDeviceStateManagerCallback)} before a
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index ee2a071..593be86 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -16,20 +16,23 @@
 
 package android.hardware.devicestate;
 
+import android.hardware.devicestate.DeviceStateInfo;
+
 /** @hide */
 interface IDeviceStateManagerCallback {
     /**
-     * Called in response to a change in device state. Guaranteed to be called once with the initial
-     * value on registration of the callback.
+     * Called in response to a change in {@link DeviceStateInfo}.
      *
-     * @param deviceState the new state of the device.
+     * @param info the new device state info.
+     *
+     * @see DeviceStateInfo
      */
-    oneway void onDeviceStateChanged(int deviceState);
+    oneway void onDeviceStateInfoChanged(in DeviceStateInfo info);
 
     /**
      * Called to notify the callback that a request has become active. Guaranteed to be called
-     * after a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming active
-     * resulted in a device state change.
+     * after a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+     * becoming active resulted in a change of device state info.
      *
      * @param token the request token previously registered with
      *        {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -38,8 +41,8 @@
 
     /**
      * Called to notify the callback that a request has become suspended. Guaranteed to be called
-     * before a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming
-     * suspended resulted in a device state change.
+     * before a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+     * becoming suspended resulted in a change of device state info.
      *
      * @param token the request token previously registered with
      *        {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -49,8 +52,8 @@
     /**
      * Called to notify the callback that a request has become canceled. No further callbacks will
      * be triggered for this request. Guaranteed to be called before a subsequent call to
-     * {@link #onDeviceStateChanged(int)} if the request becoming canceled resulted in a device
-     * state change.
+     * {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request becoming canceled resulted
+     * in a change of device state info.
      *
      * @param token the request token previously registered with
      *        {@link IDeviceStateManager#requestState(IBinder, int, int)}
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index e247df3..aafa7d5 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -537,6 +537,26 @@
     }
 
     /**
+     * Returns the minimum allowed brightness reduction strength in percentage when activated.
+     *
+     * @hide
+     */
+    public static int getMinimumReduceBrightColorsStrength(Context context) {
+        return context.getResources()
+                .getInteger(R.integer.config_reduceBrightColorsStrengthMin);
+    }
+
+    /**
+     * Returns the maximum allowed brightness reduction strength in percentage when activated.
+     *
+     * @hide
+     */
+    public static int getMaximumReduceBrightColorsStrength(Context context) {
+        return context.getResources()
+                .getInteger(R.integer.config_reduceBrightColorsStrengthMax);
+    }
+
+    /**
      * Check if the color transforms are color accelerated. Some transforms are experimental only
      * on non-accelerated platforms due to the performance implications.
      *
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 41126b7..9457d8f1 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -16,40 +16,69 @@
 
 package android.hardware.display;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Product-specific information about the display or the directly connected device on the
  * display chain. For example, if the display is transitively connected, this field may contain
  * product information about the intermediate device.
- * @hide
  */
 public final class DeviceProductInfo implements Parcelable {
+    /** @hide */
+    @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = {
+            CONNECTION_TO_SINK_UNKNOWN,
+            CONNECTION_TO_SINK_BUILT_IN,
+            CONNECTION_TO_SINK_DIRECT,
+            CONNECTION_TO_SINK_TRANSITIVE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ConnectionToSinkType { }
+
+    /** The device connection to the display sink is unknown. */
+    public static final int CONNECTION_TO_SINK_UNKNOWN =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN;
+
+    /** The display sink is built-in to the device */
+    public static final int CONNECTION_TO_SINK_BUILT_IN =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN;
+
+    /** The device is directly connected to the display sink. */
+    public static final int CONNECTION_TO_SINK_DIRECT =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT;
+
+    /** The device is transitively connected to the display sink. */
+    public static final int CONNECTION_TO_SINK_TRANSITIVE =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE;
+
     private final String mName;
     private final String mManufacturerPnpId;
     private final String mProductId;
     private final Integer mModelYear;
     private final ManufactureDate mManufactureDate;
-    private final int[] mRelativeAddress;
+    private final @ConnectionToSinkType int mConnectionToSinkType;
 
+    /** @hide */
     public DeviceProductInfo(
             String name,
             String manufacturerPnpId,
             String productId,
             Integer modelYear,
             ManufactureDate manufactureDate,
-            int[] relativeAddress) {
+            int connectionToSinkType) {
         this.mName = name;
         this.mManufacturerPnpId = manufacturerPnpId;
         this.mProductId = productId;
         this.mModelYear = modelYear;
         this.mManufactureDate = manufactureDate;
-        this.mRelativeAddress = relativeAddress;
+        this.mConnectionToSinkType = connectionToSinkType;
     }
 
     private DeviceProductInfo(Parcel in) {
@@ -58,12 +87,13 @@
         mProductId = (String) in.readValue(null);
         mModelYear = (Integer) in.readValue(null);
         mManufactureDate = (ManufactureDate) in.readValue(null);
-        mRelativeAddress = in.createIntArray();
+        mConnectionToSinkType = in.readInt();
     }
 
     /**
      * @return Display name.
      */
+    @Nullable
     public String getName() {
         return mName;
     }
@@ -71,6 +101,7 @@
     /**
      * @return Manufacturer Plug and Play ID.
      */
+    @NonNull
     public String getManufacturerPnpId() {
         return mManufacturerPnpId;
     }
@@ -78,32 +109,58 @@
     /**
      * @return Manufacturer product ID.
      */
+    @NonNull
     public String getProductId() {
         return mProductId;
     }
 
     /**
-     * @return Model year of the device. Typically exactly one of model year or
-     *      manufacture date will be present.
+     * @return Model year of the device. Return -1 if not available. Typically,
+     * one of model year or manufacture year is available.
      */
-    public Integer getModelYear() {
-        return mModelYear;
+    public int getModelYear()  {
+        return mModelYear != null ? mModelYear : -1;
+    }
+
+    /**
+     * @return The year of manufacture, or -1 it is not available. Typically,
+     * one of model year or manufacture year is available.
+     */
+    public int getManufactureYear()  {
+        if (mManufactureDate == null) {
+            return -1;
+        }
+        return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1;
+    }
+
+    /**
+     * @return The week of manufacture, or -1 it is not available. Typically,
+     * not present if model year is available.
+     */
+    public int getManufactureWeek() {
+        if (mManufactureDate == null) {
+            return -1;
+        }
+        return mManufactureDate.mWeek != null ?  mManufactureDate.mWeek : -1;
     }
 
     /**
      * @return Manufacture date. Typically exactly one of model year or manufacture
      * date will be present.
+     *
+     * @hide
      */
     public ManufactureDate getManufactureDate() {
         return mManufactureDate;
     }
 
     /**
-     * @return Relative address in the display network. For example, for HDMI connected devices this
-     * can be its physical address. Each component of the address is in the range [0, 255].
+     * @return How the current device is connected to the display sink. For example, the display
+     * can be connected immediately to the device or there can be a receiver in between.
      */
-    public int[] getRelativeAddress() {
-        return mRelativeAddress;
+    @ConnectionToSinkType
+    public int getConnectionToSinkType() {
+        return mConnectionToSinkType;
     }
 
     @Override
@@ -119,8 +176,8 @@
                 + mModelYear
                 + ", manufactureDate="
                 + mManufactureDate
-                + ", relativeAddress="
-                + Arrays.toString(mRelativeAddress)
+                + ", connectionToSinkType="
+                + mConnectionToSinkType
                 + '}';
     }
 
@@ -134,16 +191,16 @@
                 && Objects.equals(mProductId, that.mProductId)
                 && Objects.equals(mModelYear, that.mModelYear)
                 && Objects.equals(mManufactureDate, that.mManufactureDate)
-                && Arrays.equals(mRelativeAddress, that.mRelativeAddress);
+                && mConnectionToSinkType == that.mConnectionToSinkType;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate,
-            Arrays.hashCode(mRelativeAddress));
+                mConnectionToSinkType);
     }
 
-    public static final Creator<DeviceProductInfo> CREATOR =
+    @NonNull public static final Creator<DeviceProductInfo> CREATOR =
             new Creator<DeviceProductInfo>() {
                 @Override
                 public DeviceProductInfo createFromParcel(Parcel in) {
@@ -162,13 +219,13 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mName);
         dest.writeString(mManufacturerPnpId);
         dest.writeValue(mProductId);
         dest.writeValue(mModelYear);
         dest.writeValue(mManufactureDate);
-        dest.writeIntArray(mRelativeAddress);
+        dest.writeInt(mConnectionToSinkType);
     }
 
     /**
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 06b5b67..a5c9a7f 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -34,10 +34,7 @@
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
 import android.os.ParcelFileDescriptor;
 import android.os.SharedMemory;
-import android.system.ErrnoException;
 
-import java.io.FileDescriptor;
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.UUID;
@@ -111,13 +108,9 @@
         aidlModel.type = apiModel.getType();
         aidlModel.uuid = api2aidlUuid(apiModel.getUuid());
         aidlModel.vendorUuid = api2aidlUuid(apiModel.getVendorUuid());
-        try {
-            aidlModel.data = ParcelFileDescriptor.dup(
-                    byteArrayToSharedMemory(apiModel.getData(), "SoundTrigger SoundModel"));
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        aidlModel.dataSize = apiModel.getData().length;
+        byte[] data = apiModel.getData();
+        aidlModel.data = byteArrayToSharedMemory(data, "SoundTrigger SoundModel");
+        aidlModel.dataSize = data.length;
         return aidlModel;
     }
 
@@ -379,7 +372,7 @@
         return result;
     }
 
-    private static @Nullable FileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
+    private static @Nullable ParcelFileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
         if (data.length == 0) {
             return null;
         }
@@ -389,8 +382,10 @@
             ByteBuffer buffer = shmem.mapReadWrite();
             buffer.put(data);
             shmem.unmap(buffer);
-            return shmem.getFileDescriptor();
-        } catch (ErrnoException e) {
+            ParcelFileDescriptor fd = shmem.getFdDup();
+            shmem.close();
+            return fd;
+        } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 9198eb7..5cfcd66 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -171,7 +171,7 @@
                 SomeArgs args = (SomeArgs) msg.obj;
                 try {
                     inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
-                            (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
+                            (IInputMethodPrivilegedOperations) args.arg2);
                 } finally {
                     args.recycle();
                 }
@@ -280,10 +280,9 @@
     @BinderThread
     @Override
     public void initializeInternal(IBinder token, int displayId,
-            IInputMethodPrivilegedOperations privOps, int configChanges) {
+            IInputMethodPrivilegedOperations privOps) {
         mCaller.executeOrSendMessage(
-                mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
-                        configChanges));
+                mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 03dd306..7e2be01 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,7 +70,6 @@
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -132,7 +131,6 @@
 import android.window.WindowMetricsHelper;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
@@ -515,8 +513,6 @@
     private boolean mIsAutomotive;
     private Handler mHandler;
     private boolean mImeSurfaceScheduledForRemoval;
-    private Configuration mLastKnownConfig;
-    private int mHandledConfigChanges;
 
     /**
      * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -592,14 +588,12 @@
         @MainThread
         @Override
         public final void initializeInternal(@NonNull IBinder token, int displayId,
-                IInputMethodPrivilegedOperations privilegedOperations,
-                int configChanges) {
+                IInputMethodPrivilegedOperations privilegedOperations) {
             if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
                 Log.w(TAG, "The token has already registered, ignore this initialization.");
                 return;
             }
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
-            mHandledConfigChanges = configChanges;
             mPrivOps.set(privilegedOperations);
             InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
             updateInputMethodDisplay(displayId);
@@ -827,9 +821,6 @@
                 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
             }
             final boolean isVisible = isInputViewShown();
-            if (isVisible && getResources() != null) {
-                mLastKnownConfig = getResources().getConfiguration();
-            }
             final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
                 resultReceiver.send(visibilityChanged
@@ -1437,37 +1428,10 @@
      * state: {@link #onStartInput} if input is active, and
      * {@link #onCreateInputView} and {@link #onStartInputView} and related
      * appropriate functions if the UI is displayed.
-     * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
-     * changes themselves instead of being restarted with
-     * {@link android.R.styleable#InputMethod_configChanges}.
      */
     @Override public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        if (shouldImeRestartForConfig(newConfig)) {
-            resetStateForNewConfiguration();
-        }
-    }
-
-    /**
-     * @return {@code true} if {@link InputMethodService} needs to restart to handle
-     * .{@link #onConfigurationChanged(Configuration)}
-     */
-    @VisibleForTesting
-    boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
-        if (mLastKnownConfig == null) {
-            return true;
-        }
-        // If the new config is the same as the config this Service is already running with,
-        // then don't bother calling resetStateForNewConfiguration.
-        int diff = mLastKnownConfig.diffPublicOnly(newConfig);
-        if (diff != 0) {
-            // remove attrs not-relevant to IME service.
-            diff &= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
-            diff &= ActivityInfo.CONFIG_KEYBOARD;
-            diff &= ActivityInfo.CONFIG_NAVIGATION;
-        }
-        int unhandledDiff = (diff & ~mHandledConfigChanges);
-        return unhandledDiff != 0;
+        resetStateForNewConfiguration();
     }
 
     private void resetStateForNewConfiguration() {
@@ -3217,17 +3181,7 @@
             requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
         }
     }
-
-    @VisibleForTesting
-    void setLastKnownConfig(@NonNull Configuration config) {
-        mLastKnownConfig = config;
-    }
-
-    @VisibleForTesting
-    void setHandledConfigChanges(int configChanges) {
-        mHandledConfigChanges = configChanges;
-    }
-
+    
     void startExtractingText(boolean inputChanged) {
         final ExtractEditText eet = mExtractEditText;
         if (eet != null && getCurrentInputStarted()
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 0baf11e..dc3b88a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -19,7 +19,7 @@
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsSession;
 import android.net.Network;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -68,7 +68,7 @@
     /** Force update of ifaces. */
     void forceUpdateIfaces(
          in Network[] defaultNetworks,
-         in NetworkState[] networkStates,
+         in NetworkStateSnapshot[] snapshots,
          in String activeIface,
          in UnderlyingNetworkInfo[] underlyingNetworkInfos);
     /** Force update of statistics. */
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 183f500..cc1312b 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -24,10 +24,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.keystore.AndroidKeyStoreProvider;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.VpnProfile;
@@ -35,7 +32,9 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
+import java.security.Key;
 import java.security.KeyFactory;
+import java.security.KeyStore;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.cert.CertificateEncodingException;
@@ -66,6 +65,7 @@
     /** Prefix for when a Private Key is stored directly in the profile @hide */
     public static final String PREFIX_INLINE = "INLINE:";
 
+    private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
     private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s";
     private static final String EMPTY_CERT = "";
 
@@ -430,32 +430,31 @@
         return profile;
     }
 
-    /**
-     * Constructs a Ikev2VpnProfile from an internal-use VpnProfile instance.
-     *
-     * <p>Redundant authentication information (not related to profile type) will be discarded.
-     *
-     * @hide
-     */
-    @NonNull
-    public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
-            throws IOException, GeneralSecurityException {
-        return fromVpnProfile(profile, null);
+    private static PrivateKey getPrivateKeyFromAndroidKeystore(String alias) {
+        try {
+            final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER);
+            keystore.load(null);
+            final Key key = keystore.getKey(alias, null);
+            if (!(key instanceof PrivateKey)) {
+                throw new IllegalStateException(
+                        "Unexpected key type returned from android keystore.");
+            }
+            return (PrivateKey) key;
+        } catch (Exception e) {
+            throw new IllegalStateException("Failed to load key from android keystore.", e);
+        }
     }
 
     /**
      * Builds the Ikev2VpnProfile from the given profile.
      *
      * @param profile the source VpnProfile to build from
-     * @param keyStore the Android Keystore instance to use to retrieve the private key, or null if
-     *     the private key is PEM-encoded into the profile.
      * @return The IKEv2/IPsec VPN profile
      * @hide
      */
     @NonNull
-    public static Ikev2VpnProfile fromVpnProfile(
-            @NonNull VpnProfile profile, @Nullable KeyStore keyStore)
-            throws IOException, GeneralSecurityException {
+    public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
+            throws GeneralSecurityException {
         final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
         builder.setProxy(profile.proxy);
         builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
@@ -479,12 +478,9 @@
             case TYPE_IKEV2_IPSEC_RSA:
                 final PrivateKey key;
                 if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) {
-                    Objects.requireNonNull(keyStore, "Missing Keystore for aliased PrivateKey");
-
                     final String alias =
                             profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length());
-                    key = AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
-                            keyStore, alias, Process.myUid());
+                    key = getPrivateKeyFromAndroidKeystore(alias);
                 } else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) {
                     key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length()));
                 } else {
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index e89451e..268002f 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -146,6 +146,25 @@
     public static final String AUTH_AES_XCBC = "xcbc(aes)";
 
     /**
+     * AES-CMAC Authentication/Integrity Algorithm.
+     *
+     * <p>Keys for this algorithm must be 128 bits in length.
+     *
+     * <p>The only valid truncation length is 96 bits.
+     *
+     * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
+     * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
+     * included in the returned algorithm set. The returned algorithm set will not change unless the
+     * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
+     * requested on an unsupported device.
+     *
+     * <p>@see {@link #getSupportedAlgorithms()}
+     */
+    // This algorithm may be available on devices released before Android 12, and is guaranteed
+    // to be available on devices first shipped with Android 12 or later.
+    public static final String AUTH_AES_CMAC = "cmac(aes)";
+
+    /**
      * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
      *
      * <p>Valid lengths for keying material are {160, 224, 288}.
@@ -191,6 +210,7 @@
         AUTH_HMAC_SHA384,
         AUTH_HMAC_SHA512,
         AUTH_AES_XCBC,
+        AUTH_AES_CMAC,
         AUTH_CRYPT_AES_GCM,
         AUTH_CRYPT_CHACHA20_POLY1305
     })
@@ -212,10 +232,10 @@
         ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
         ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
 
-        // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined
-        ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
     }
 
     private static final Set<String> ENABLED_ALGOS =
@@ -383,6 +403,10 @@
                 isValidLen = keyLen == 128;
                 isValidTruncLen = truncLen == 96;
                 break;
+            case AUTH_AES_CMAC:
+                isValidLen = keyLen == 128;
+                isValidTruncLen = truncLen == 96;
+                break;
             case AUTH_CRYPT_AES_GCM:
                 // The keying material for GCM is a key plus a 32-bit salt
                 isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
@@ -416,6 +440,7 @@
             case AUTH_HMAC_SHA384:
             case AUTH_HMAC_SHA512:
             case AUTH_AES_XCBC:
+            case AUTH_AES_CMAC:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 303a407..a5ece7b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -18,7 +18,6 @@
 
 import static android.net.ConnectivityManager.TYPE_WIFI;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.wifi.WifiInfo;
@@ -180,29 +179,42 @@
     }
 
     /**
-     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
-     * assuming that any mobile networks are using the current IMSI. The subType if applicable,
-     * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
-     * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
+     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and
+     * {@code subType}, assuming that any mobile networks are using the current IMSI.
+     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
+     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
      */
-    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
-            boolean defaultNetwork, @NetworkType int subType) {
-        final int legacyType = state.legacyNetworkType;
+    // TODO: Delete this function after NetworkPolicyManagerService finishes the migration.
+    public static NetworkIdentity buildNetworkIdentity(Context context,
+            NetworkState state, boolean defaultNetwork, @NetworkType int subType) {
+        final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
+                state.networkCapabilities, state.linkProperties, state.subscriberId,
+                state.legacyNetworkType);
+        return buildNetworkIdentity(context, snapshot, defaultNetwork, subType);
+    }
 
-        String subscriberId = null;
+    /**
+     * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and
+     * {@code subType}, assuming that any mobile networks are using the current IMSI.
+     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
+     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
+     */
+    public static NetworkIdentity buildNetworkIdentity(Context context,
+            NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) {
+        final int legacyType = snapshot.legacyType;
+
+        final String subscriberId = snapshot.subscriberId;
         String networkId = null;
-        boolean roaming = !state.networkCapabilities.hasCapability(
+        boolean roaming = !snapshot.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
-        boolean metered = !state.networkCapabilities.hasCapability(
+        boolean metered = !snapshot.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
 
-        subscriberId = state.subscriberId;
-
-        final int oemManaged = getOemBitfield(state.networkCapabilities);
+        final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
 
         if (legacyType == TYPE_WIFI) {
-            if (state.networkCapabilities.getSsid() != null) {
-                networkId = state.networkCapabilities.getSsid();
+            if (snapshot.networkCapabilities.getSsid() != null) {
+                networkId = snapshot.networkCapabilities.getSsid();
                 if (networkId == null) {
                     // TODO: Figure out if this code path never runs. If so, remove them.
                     final WifiManager wifi = (WifiManager) context.getSystemService(
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
index 881b373..b3d8d4e 100644
--- a/core/java/android/net/NetworkStateSnapshot.java
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -16,8 +16,11 @@
 
 package android.net;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,31 +31,49 @@
  *
  * @hide
  */
+@SystemApi(client = MODULE_LIBRARIES)
 public final class NetworkStateSnapshot implements Parcelable {
-    @NonNull
-    public final LinkProperties linkProperties;
-    @NonNull
-    public final NetworkCapabilities networkCapabilities;
+    /** The network associated with this snapshot. */
     @NonNull
     public final Network network;
+
+    /** The {@link NetworkCapabilities} of the network associated with this snapshot. */
+    @NonNull
+    public final NetworkCapabilities networkCapabilities;
+
+    /** The {@link LinkProperties} of the network associated with this snapshot. */
+    @NonNull
+    public final LinkProperties linkProperties;
+
+    /**
+     * The Subscriber Id of the network associated with this snapshot. See
+     * {@link android.telephony.TelephonyManager#getSubscriberId()}.
+     */
     @Nullable
     public final String subscriberId;
+
+    /**
+     * The legacy type of the network associated with this snapshot. See
+     * {@code ConnectivityManager#TYPE_*}.
+     */
     public final int legacyType;
 
-    public NetworkStateSnapshot(@NonNull LinkProperties linkProperties,
-            @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+    public NetworkStateSnapshot(@NonNull Network network,
+            @NonNull NetworkCapabilities networkCapabilities,
+            @NonNull LinkProperties linkProperties,
             @Nullable String subscriberId, int legacyType) {
-        this.linkProperties = Objects.requireNonNull(linkProperties);
-        this.networkCapabilities = Objects.requireNonNull(networkCapabilities);
         this.network = Objects.requireNonNull(network);
+        this.networkCapabilities = Objects.requireNonNull(networkCapabilities);
+        this.linkProperties = Objects.requireNonNull(linkProperties);
         this.subscriberId = subscriberId;
         this.legacyType = legacyType;
     }
 
+    /** @hide */
     public NetworkStateSnapshot(@NonNull Parcel in) {
-        linkProperties = in.readParcelable(null);
-        networkCapabilities = in.readParcelable(null);
         network = in.readParcelable(null);
+        networkCapabilities = in.readParcelable(null);
+        linkProperties = in.readParcelable(null);
         subscriberId = in.readString();
         legacyType = in.readInt();
     }
@@ -64,9 +85,9 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
-        out.writeParcelable(linkProperties, flags);
-        out.writeParcelable(networkCapabilities, flags);
         out.writeParcelable(network, flags);
+        out.writeParcelable(networkCapabilities, flags);
+        out.writeParcelable(linkProperties, flags);
         out.writeString(subscriberId);
         out.writeInt(legacyType);
     }
@@ -93,14 +114,14 @@
         if (!(o instanceof NetworkStateSnapshot)) return false;
         NetworkStateSnapshot that = (NetworkStateSnapshot) o;
         return legacyType == that.legacyType
-                && Objects.equals(linkProperties, that.linkProperties)
-                && Objects.equals(networkCapabilities, that.networkCapabilities)
                 && Objects.equals(network, that.network)
+                && Objects.equals(networkCapabilities, that.networkCapabilities)
+                && Objects.equals(linkProperties, that.linkProperties)
                 && Objects.equals(subscriberId, that.subscriberId);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(linkProperties, networkCapabilities, network, subscriberId, legacyType);
+        return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType);
     }
 }
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
index b403455..48bd297 100644
--- a/core/java/android/net/OemNetworkPreferences.java
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -29,7 +29,15 @@
 import java.util.Map;
 import java.util.Objects;
 
-/** @hide */
+/**
+ * Network preferences to set the default active network on a per-application basis as per a given
+ * {@link OemNetworkPreference}. An example of this would be to set an application's network
+ * preference to {@link #OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK} which would have the default
+ * network for that application set to an unmetered network first if available and if not, it then
+ * set that application's default network to an OEM managed network if available.
+ *
+ * @hide
+ */
 @SystemApi
 public final class OemNetworkPreferences implements Parcelable {
     /**
@@ -64,6 +72,10 @@
     @NonNull
     private final Bundle mNetworkMappings;
 
+    /**
+     * Return the currently built application package name to {@link OemNetworkPreference} mappings.
+     * @return the current network preferences map.
+     */
     @NonNull
     public Map<String, Integer> getNetworkPreferences() {
         return convertToUnmodifiableMap(mNetworkMappings);
@@ -105,6 +117,11 @@
             mNetworkMappings = new Bundle();
         }
 
+        /**
+         * Constructor to populate the builder's values with an already built
+         * {@link OemNetworkPreferences}.
+         * @param preferences the {@link OemNetworkPreferences} to populate with.
+         */
         public Builder(@NonNull final OemNetworkPreferences preferences) {
             Objects.requireNonNull(preferences);
             mNetworkMappings = (Bundle) preferences.mNetworkMappings.clone();
diff --git a/packages/Connectivity/framework/src/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/PacProxySelector.java
rename to core/java/android/net/PacProxySelector.java
diff --git a/packages/Connectivity/framework/src/android/net/Proxy.java b/core/java/android/net/Proxy.java
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/Proxy.java
rename to core/java/android/net/Proxy.java
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index f90fbaf..fa3ff8a 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -41,6 +41,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.net.VpnConfig;
 
 import java.net.DatagramSocket;
@@ -254,7 +255,7 @@
      * @return {@code true} on success.
      */
     public boolean protect(int socket) {
-        return NetworkUtils.protectFromVpn(socket);
+        return NetworkUtilsInternal.protectFromVpn(socket);
     }
 
     /**
diff --git a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
similarity index 97%
rename from packages/Connectivity/framework/src/android/net/util/SocketUtils.java
rename to core/java/android/net/util/SocketUtils.java
index e64060f..69edc75 100644
--- a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -22,12 +22,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.net.NetworkUtils;
 import android.system.ErrnoException;
 import android.system.NetlinkSocketAddress;
 import android.system.Os;
 import android.system.PacketSocketAddress;
 
+import com.android.internal.net.NetworkUtilsInternal;
+
 import libcore.io.IoBridge;
 
 import java.io.FileDescriptor;
@@ -51,7 +52,7 @@
         // of struct ifreq is a NULL-terminated interface name.
         // TODO: add a setsockoptString()
         Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface);
-        NetworkUtils.protectFromVpn(socket);
+        NetworkUtilsInternal.protectFromVpn(socket);
     }
 
     /**
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
index d91cef5..236ae8b 100644
--- a/core/java/android/net/vcn/IVcnStatusCallback.aidl
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -18,7 +18,6 @@
 
 /** @hide */
 oneway interface IVcnStatusCallback {
-    void onEnteredSafeMode();
     void onVcnStatusChanged(int statusCode);
     void onGatewayConnectionError(
             in int[] gatewayNetworkCapabilities,
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index eb8c251..8ebf757 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -359,8 +359,6 @@
     /**
      * Value indicating that the VCN for the subscription group is not configured, or that the
      * callback is not privileged for the subscription group.
-     *
-     * @hide
      */
     public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0;
 
@@ -369,8 +367,6 @@
      *
      * <p>A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the
      * provisioning package is not privileged.
-     *
-     * @hide
      */
     public static final int VCN_STATUS_CODE_INACTIVE = 1;
 
@@ -380,8 +376,6 @@
      * <p>A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning
      * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered
      * active while it is connecting, fully connected, and disconnecting.
-     *
-     * @hide
      */
     public static final int VCN_STATUS_CODE_ACTIVE = 2;
 
@@ -391,8 +385,6 @@
      * <p>A VCN will be put into Safe Mode if any of the gateway connections were unable to
      * establish a connection within a system-determined timeout (while underlying networks were
      * available).
-     *
-     * @hide
      */
     public static final int VCN_STATUS_CODE_SAFE_MODE = 3;
 
@@ -407,8 +399,6 @@
 
     /**
      * Value indicating that an internal failure occurred in this Gateway Connection.
-     *
-     * @hide
      */
     public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0;
 
@@ -416,8 +406,6 @@
      * Value indicating that an error with this Gateway Connection's configuration occurred.
      *
      * <p>For example, this error code will be returned after authentication failures.
-     *
-     * @hide
      */
     public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1;
 
@@ -427,38 +415,19 @@
      * <p>For example, this error code will be returned if an underlying {@link android.net.Network}
      * for this Gateway Connection is lost, or if an error occurs while resolving the connection
      * endpoint address.
-     *
-     * @hide
      */
     public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2;
 
-    // TODO: make VcnStatusCallback @SystemApi
     /**
      * VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs.
      *
      * <p>VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a
      * subscription group.
-     *
-     * @hide
      */
     public abstract static class VcnStatusCallback {
         private VcnStatusCallbackBinder mCbBinder;
 
         /**
-         * Invoked when the VCN for this Callback's subscription group enters safe mode.
-         *
-         * <p>A VCN will be put into safe mode if any of the gateway connections were unable to
-         * establish a connection within a system-determined timeout (while underlying networks were
-         * available).
-         *
-         * <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration
-         * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}.
-         *
-         * @hide
-         */
-        public void onEnteredSafeMode() {}
-
-        /**
          * Invoked when status of the VCN for this callback's subscription group changes.
          *
          * @param statusCode the code for the status change encountered by this {@link
@@ -467,15 +436,16 @@
         public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode);
 
         /**
-         * Invoked when a VCN Gateway Connection corresponding to this callback's subscription
+         * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
          * encounters an error.
          *
-         * @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway
-         *     Connection that encountered the error for identification purposes. These will be a
-         *     sorted list with no duplicates, matching one of the {@link
+         * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
+         *     for the Gateway Connection that encountered the error, for identification purposes.
+         *     These will be a sorted list with no duplicates and will match {@link
+         *     VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link
          *     VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
          *     group.
-         * @param errorCode {@link VcnErrorCode} to indicate the error that occurred
+         * @param errorCode the code to indicate the error that occurred
          * @param detail Throwable to provide additional information about the error, or {@code
          *     null} if none
          */
@@ -496,6 +466,10 @@
      * <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier
      * privileges for the specified subscription at the time of invocation.
      *
+     * <p>A {@link VcnStatusCallback} is eligible to begin receiving callbacks once it is registered
+     * and there is a VCN active for its specified subscription group (this may happen after the
+     * callback is registered).
+     *
      * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the
      * current status for the specified subscription group's VCN. If the registrant is not
      * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be
@@ -505,7 +479,6 @@
      * @param executor The {@link Executor} to be used for invoking callbacks
      * @param callback The VcnStatusCallback to be registered
      * @throws IllegalStateException if callback is currently registered with VcnManager
-     * @hide
      */
     public void registerVcnStatusCallback(
             @NonNull ParcelUuid subscriptionGroup,
@@ -538,7 +511,6 @@
      * was registered with.
      *
      * @param callback The callback to be unregistered
-     * @hide
      */
     public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) {
         requireNonNull(callback, "callback must not be null");
@@ -599,12 +571,6 @@
         }
 
         @Override
-        public void onEnteredSafeMode() {
-            Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
-        }
-
-        @Override
         public void onVcnStatusChanged(@VcnStatusCode int statusCode) {
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode)));
diff --git a/core/java/android/net/vcn/persistablebundleutils/CertUtils.java b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
new file mode 100644
index 0000000..b6036b4
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+/**
+ * CertUtils provides utility methods for constructing Certificate.
+ *
+ * @hide
+ */
+public class CertUtils {
+    private static final String CERT_TYPE_X509 = "X.509";
+
+    /** Decodes an ASN.1 DER encoded Certificate */
+    public static X509Certificate certificateFromByteArray(byte[] derEncoded) {
+        Objects.requireNonNull(derEncoded, "derEncoded is null");
+
+        try {
+            CertificateFactory certFactory = CertificateFactory.getInstance(CERT_TYPE_X509);
+            InputStream in = new ByteArrayInputStream(derEncoded);
+            return (X509Certificate) certFactory.generateCertificate(in);
+        } catch (CertificateException e) {
+            throw new IllegalArgumentException("Fail to decode certificate", e);
+        }
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
new file mode 100644
index 0000000..ce5ec75
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert ChildSaProposal to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class ChildSaProposalUtils extends SaProposalUtilsBase {
+    /** Serializes a ChildSaProposal to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(ChildSaProposal proposal) {
+        return SaProposalUtilsBase.toPersistableBundle(proposal);
+    }
+
+    /** Constructs a ChildSaProposal by deserializing a PersistableBundle. */
+    @NonNull
+    public static ChildSaProposal fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        final ChildSaProposal.Builder builder = new ChildSaProposal.Builder();
+
+        final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY);
+        Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null");
+        final List<EncryptionAlgoKeyLenPair> encryptList =
+                PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new);
+        for (EncryptionAlgoKeyLenPair t : encryptList) {
+            builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen);
+        }
+
+        final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY);
+        Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null");
+        for (int algo : integrityAlgoIdArray) {
+            builder.addIntegrityAlgorithm(algo);
+        }
+
+        final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY);
+        Objects.requireNonNull(dhGroupArray, "DH Group array was null");
+        for (int dh : dhGroupArray) {
+            builder.addDhGroup(dh);
+        }
+
+        return builder.build();
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
new file mode 100644
index 0000000..853a52d
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.eap.EapSessionConfig;
+import android.net.eap.EapSessionConfig.EapAkaConfig;
+import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
+import android.net.eap.EapSessionConfig.EapMethodConfig;
+import android.net.eap.EapSessionConfig.EapMsChapV2Config;
+import android.net.eap.EapSessionConfig.EapSimConfig;
+import android.net.eap.EapSessionConfig.EapTtlsConfig;
+import android.net.eap.EapSessionConfig.EapUiccConfig;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert EapSessionConfig to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class EapSessionConfigUtils {
+    private static final String EAP_ID_KEY = "EAP_ID_KEY";
+    private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY";
+    private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY";
+    private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY";
+    private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY";
+    private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY";
+
+    /** Serializes an EapSessionConfig to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(@NonNull EapSessionConfig config) {
+        final PersistableBundle result = new PersistableBundle();
+
+        result.putPersistableBundle(
+                EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity()));
+
+        if (config.getEapSimConfig() != null) {
+            result.putPersistableBundle(
+                    EAP_SIM_CONFIG_KEY,
+                    EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig()));
+        }
+
+        if (config.getEapTtlsConfig() != null) {
+            result.putPersistableBundle(
+                    EAP_TTLS_CONFIG_KEY,
+                    EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig()));
+        }
+
+        if (config.getEapAkaConfig() != null) {
+            result.putPersistableBundle(
+                    EAP_AKA_CONFIG_KEY,
+                    EapAkaConfigUtils.toPersistableBundle(config.getEapAkaConfig()));
+        }
+
+        if (config.getEapMsChapV2Config() != null) {
+            result.putPersistableBundle(
+                    EAP_MSCHAP_V2_CONFIG_KEY,
+                    EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config()));
+        }
+
+        if (config.getEapAkaPrimeConfig() != null) {
+            result.putPersistableBundle(
+                    EAP_AKA_PRIME_CONFIG_KEY,
+                    EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig()));
+        }
+
+        return result;
+    }
+
+    /** Constructs an EapSessionConfig by deserializing a PersistableBundle. */
+    @NonNull
+    public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        final EapSessionConfig.Builder builder = new EapSessionConfig.Builder();
+
+        final PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY);
+        Objects.requireNonNull(eapIdBundle, "EAP ID was null");
+        builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle));
+
+        final PersistableBundle simBundle = in.getPersistableBundle(EAP_SIM_CONFIG_KEY);
+        if (simBundle != null) {
+            EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder);
+        }
+
+        final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY);
+        if (ttlsBundle != null) {
+            EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder);
+        }
+
+        final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY);
+        if (akaBundle != null) {
+            EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder);
+        }
+
+        final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY);
+        if (msChapV2Bundle != null) {
+            EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder);
+        }
+
+        final PersistableBundle akaPrimeBundle = in.getPersistableBundle(EAP_AKA_PRIME_CONFIG_KEY);
+        if (akaPrimeBundle != null) {
+            EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder);
+        }
+
+        return builder.build();
+    }
+
+    private static class EapMethodConfigUtils {
+        private static final String METHOD_TYPE = "METHOD_TYPE";
+
+        /** Serializes an EapMethodConfig to a PersistableBundle. */
+        @NonNull
+        public static PersistableBundle toPersistableBundle(@NonNull EapMethodConfig config) {
+            final PersistableBundle result = new PersistableBundle();
+            result.putInt(METHOD_TYPE, config.getMethodType());
+            return result;
+        }
+    }
+
+    private static class EapUiccConfigUtils extends EapMethodConfigUtils {
+        static final String SUB_ID_KEY = "SUB_ID_KEY";
+        static final String APP_TYPE_KEY = "APP_TYPE_KEY";
+
+        @NonNull
+        protected static PersistableBundle toPersistableBundle(@NonNull EapUiccConfig config) {
+            final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
+            result.putInt(SUB_ID_KEY, config.getSubId());
+            result.putInt(APP_TYPE_KEY, config.getAppType());
+
+            return result;
+        }
+    }
+
+    private static final class EapSimConfigUtils extends EapUiccConfigUtils {
+        @NonNull
+        public static PersistableBundle toPersistableBundle(EapSimConfig config) {
+            return EapUiccConfigUtils.toPersistableBundle(config);
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+            builder.setEapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY));
+        }
+    }
+
+    private static class EapAkaConfigUtils extends EapUiccConfigUtils {
+        @NonNull
+        public static PersistableBundle toPersistableBundle(@NonNull EapAkaConfig config) {
+            return EapUiccConfigUtils.toPersistableBundle(config);
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+            builder.setEapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY));
+        }
+    }
+
+    private static final class EapAkaPrimeConfigUtils extends EapAkaConfigUtils {
+        private static final String NETWORK_NAME_KEY = "NETWORK_NAME_KEY";
+        private static final String ALL_MISMATCHED_NETWORK_KEY = "ALL_MISMATCHED_NETWORK_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(@NonNull EapAkaPrimeConfig config) {
+            final PersistableBundle result = EapUiccConfigUtils.toPersistableBundle(config);
+            result.putString(NETWORK_NAME_KEY, config.getNetworkName());
+            result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, config.allowsMismatchedNetworkNames());
+
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+            builder.setEapAkaPrimeConfig(
+                    in.getInt(SUB_ID_KEY),
+                    in.getInt(APP_TYPE_KEY),
+                    in.getString(NETWORK_NAME_KEY),
+                    in.getBoolean(ALL_MISMATCHED_NETWORK_KEY));
+        }
+    }
+
+    private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils {
+        private static final String USERNAME_KEY = "USERNAME_KEY";
+        private static final String PASSWORD_KEY = "PASSWORD_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(@NonNull EapMsChapV2Config config) {
+            final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
+            result.putString(USERNAME_KEY, config.getUsername());
+            result.putString(PASSWORD_KEY, config.getPassword());
+
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+            builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY));
+        }
+    }
+
+    private static final class EapTtlsConfigUtils extends EapMethodConfigUtils {
+        private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
+        private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY";
+
+        @NonNull
+        public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) {
+            final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
+            try {
+                if (config.getServerCaCert() != null) {
+                    final PersistableBundle caBundle =
+                            PersistableBundleUtils.fromByteArray(
+                                    config.getServerCaCert().getEncoded());
+                    result.putPersistableBundle(TRUST_CERT_KEY, caBundle);
+                }
+            } catch (CertificateEncodingException e) {
+                throw new IllegalStateException("Fail to encode the certificate");
+            }
+
+            result.putPersistableBundle(
+                    EAP_SESSION_CONFIG_KEY,
+                    EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig()));
+
+            return result;
+        }
+
+        public static void setBuilderByReadingPersistableBundle(
+                @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+
+            final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY);
+            X509Certificate caCert = null;
+            if (caBundle != null) {
+                caCert =
+                        CertUtils.certificateFromByteArray(
+                                PersistableBundleUtils.toByteArray(caBundle));
+            }
+
+            final PersistableBundle eapSessionConfigBundle =
+                    in.getPersistableBundle(EAP_SESSION_CONFIG_KEY);
+            Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null");
+            final EapSessionConfig eapSessionConfig =
+                    EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle);
+
+            builder.setEapTtlsConfig(caCert, eapSessionConfig);
+        }
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
new file mode 100644
index 0000000..6acb34e
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeIdentification;
+import android.net.ipsec.ike.IkeIpv4AddrIdentification;
+import android.net.ipsec.ike.IkeIpv6AddrIdentification;
+import android.net.ipsec.ike.IkeKeyIdIdentification;
+import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.Objects;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Abstract utility class to convert IkeIdentification to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeIdentificationUtils {
+    private static final String ID_TYPE_KEY = "ID_TYPE_KEY";
+
+    private static final String DER_ASN1_DN_KEY = "DER_ASN1_DN_KEY";
+    private static final String FQDN_KEY = "FQDN_KEY";
+    private static final String KEY_ID_KEY = "KEY_ID_KEY";
+    private static final String IP4_ADDRESS_KEY = "IP4_ADDRESS_KEY";
+    private static final String IP6_ADDRESS_KEY = "IP6_ADDRESS_KEY";
+    private static final String RFC822_ADDRESS_KEY = "RFC822_ADDRESS_KEY";
+
+    private static final int ID_TYPE_DER_ASN1_DN = 1;
+    private static final int ID_TYPE_FQDN = 2;
+    private static final int ID_TYPE_IPV4_ADDR = 3;
+    private static final int ID_TYPE_IPV6_ADDR = 4;
+    private static final int ID_TYPE_KEY_ID = 5;
+    private static final int ID_TYPE_RFC822_ADDR = 6;
+
+    /** Serializes an IkeIdentification to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(@NonNull IkeIdentification ikeId) {
+        if (ikeId instanceof IkeDerAsn1DnIdentification) {
+            final PersistableBundle result = createPersistableBundle(ID_TYPE_DER_ASN1_DN);
+            IkeDerAsn1DnIdentification id = (IkeDerAsn1DnIdentification) ikeId;
+            result.putPersistableBundle(
+                    DER_ASN1_DN_KEY,
+                    PersistableBundleUtils.fromByteArray(id.derAsn1Dn.getEncoded()));
+            return result;
+        } else if (ikeId instanceof IkeFqdnIdentification) {
+            final PersistableBundle result = createPersistableBundle(ID_TYPE_FQDN);
+            IkeFqdnIdentification id = (IkeFqdnIdentification) ikeId;
+            result.putString(FQDN_KEY, id.fqdn);
+            return result;
+        } else if (ikeId instanceof IkeIpv4AddrIdentification) {
+            final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV4_ADDR);
+            IkeIpv4AddrIdentification id = (IkeIpv4AddrIdentification) ikeId;
+            result.putString(IP4_ADDRESS_KEY, id.ipv4Address.getHostAddress());
+            return result;
+        } else if (ikeId instanceof IkeIpv6AddrIdentification) {
+            final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV6_ADDR);
+            IkeIpv6AddrIdentification id = (IkeIpv6AddrIdentification) ikeId;
+            result.putString(IP6_ADDRESS_KEY, id.ipv6Address.getHostAddress());
+            return result;
+        } else if (ikeId instanceof IkeKeyIdIdentification) {
+            final PersistableBundle result = createPersistableBundle(ID_TYPE_KEY_ID);
+            IkeKeyIdIdentification id = (IkeKeyIdIdentification) ikeId;
+            result.putPersistableBundle(KEY_ID_KEY, PersistableBundleUtils.fromByteArray(id.keyId));
+            return result;
+        } else if (ikeId instanceof IkeRfc822AddrIdentification) {
+            final PersistableBundle result = createPersistableBundle(ID_TYPE_RFC822_ADDR);
+            IkeRfc822AddrIdentification id = (IkeRfc822AddrIdentification) ikeId;
+            result.putString(RFC822_ADDRESS_KEY, id.rfc822Name);
+            return result;
+        } else {
+            throw new IllegalStateException("Unrecognized IkeIdentification subclass");
+        }
+    }
+
+    private static PersistableBundle createPersistableBundle(int idType) {
+        final PersistableBundle result = new PersistableBundle();
+        result.putInt(ID_TYPE_KEY, idType);
+        return result;
+    }
+
+    /** Constructs an IkeIdentification by deserializing a PersistableBundle. */
+    @NonNull
+    public static IkeIdentification fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+        int idType = in.getInt(ID_TYPE_KEY);
+        switch (idType) {
+            case ID_TYPE_DER_ASN1_DN:
+                final PersistableBundle dnBundle = in.getPersistableBundle(DER_ASN1_DN_KEY);
+                Objects.requireNonNull(dnBundle, "ASN1 DN was null");
+                return new IkeDerAsn1DnIdentification(
+                        new X500Principal(PersistableBundleUtils.toByteArray(dnBundle)));
+            case ID_TYPE_FQDN:
+                return new IkeFqdnIdentification(in.getString(FQDN_KEY));
+            case ID_TYPE_IPV4_ADDR:
+                final String v4AddressStr = in.getString(IP4_ADDRESS_KEY);
+                Objects.requireNonNull(v4AddressStr, "IPv4 address was null");
+                return new IkeIpv4AddrIdentification(
+                        (Inet4Address) InetAddresses.parseNumericAddress(v4AddressStr));
+            case ID_TYPE_IPV6_ADDR:
+                final String v6AddressStr = in.getString(IP6_ADDRESS_KEY);
+                Objects.requireNonNull(v6AddressStr, "IPv6 address was null");
+                return new IkeIpv6AddrIdentification(
+                        (Inet6Address) InetAddresses.parseNumericAddress(v6AddressStr));
+            case ID_TYPE_KEY_ID:
+                final PersistableBundle keyIdBundle = in.getPersistableBundle(KEY_ID_KEY);
+                Objects.requireNonNull(in, "Key ID was null");
+                return new IkeKeyIdIdentification(PersistableBundleUtils.toByteArray(keyIdBundle));
+            case ID_TYPE_RFC822_ADDR:
+                return new IkeRfc822AddrIdentification(in.getString(RFC822_ADDRESS_KEY));
+            default:
+                throw new IllegalStateException("Unrecognized IKE ID type: " + idType);
+        }
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
new file mode 100644
index 0000000..1459671
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert IkeSaProposal to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeSaProposalUtils extends SaProposalUtilsBase {
+    private static final String PRF_KEY = "PRF_KEY";
+
+    /** Serializes an IkeSaProposal to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(IkeSaProposal proposal) {
+        final PersistableBundle result = SaProposalUtilsBase.toPersistableBundle(proposal);
+
+        final int[] prfArray =
+                proposal.getPseudorandomFunctions().stream().mapToInt(i -> i).toArray();
+        result.putIntArray(PRF_KEY, prfArray);
+
+        return result;
+    }
+
+    /** Constructs an IkeSaProposal by deserializing a PersistableBundle. */
+    @NonNull
+    public static IkeSaProposal fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        final IkeSaProposal.Builder builder = new IkeSaProposal.Builder();
+
+        final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY);
+        Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null");
+        final List<EncryptionAlgoKeyLenPair> encryptList =
+                PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new);
+        for (EncryptionAlgoKeyLenPair t : encryptList) {
+            builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen);
+        }
+
+        final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY);
+        Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null");
+        for (int algo : integrityAlgoIdArray) {
+            builder.addIntegrityAlgorithm(algo);
+        }
+
+        final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY);
+        Objects.requireNonNull(dhGroupArray, "DH Group array was null");
+        for (int dh : dhGroupArray) {
+            builder.addDhGroup(dh);
+        }
+
+        final int[] prfArray = in.getIntArray(PRF_KEY);
+        Objects.requireNonNull(prfArray, "PRF array was null");
+        for (int prf : prfArray) {
+            builder.addPseudorandomFunction(prf);
+        }
+
+        return builder.build();
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java
new file mode 100644
index 0000000..6bbc6b1
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert IkeTrafficSelector to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeTrafficSelectorUtils {
+    private static final String START_PORT_KEY = "START_PORT_KEY";
+    private static final String END_PORT_KEY = "END_PORT_KEY";
+    private static final String START_ADDRESS_KEY = "START_ADDRESS_KEY";
+    private static final String END_ADDRESS_KEY = "END_ADDRESS_KEY";
+
+    /** Constructs an IkeTrafficSelector by deserializing a PersistableBundle. */
+    @NonNull
+    public static IkeTrafficSelector fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        final int startPort = in.getInt(START_PORT_KEY);
+        final int endPort = in.getInt(END_PORT_KEY);
+
+        final String startingAddress = in.getString(START_ADDRESS_KEY);
+        final String endingAddress = in.getString(END_ADDRESS_KEY);
+        Objects.requireNonNull(startingAddress, "startAddress was null");
+        Objects.requireNonNull(startingAddress, "endAddress was null");
+
+        return new IkeTrafficSelector(
+                startPort,
+                endPort,
+                InetAddresses.parseNumericAddress(startingAddress),
+                InetAddresses.parseNumericAddress(endingAddress));
+    }
+
+    /** Serializes an IkeTrafficSelector to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(@NonNull IkeTrafficSelector ts) {
+        final PersistableBundle result = new PersistableBundle();
+
+        result.putInt(START_PORT_KEY, ts.startPort);
+        result.putInt(END_PORT_KEY, ts.endPort);
+        result.putString(START_ADDRESS_KEY, ts.startingAddress.getHostAddress());
+        result.putString(END_ADDRESS_KEY, ts.endingAddress.getHostAddress());
+
+        return result;
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
new file mode 100644
index 0000000..0c9ee84
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.SaProposal;
+import android.os.PersistableBundle;
+import android.util.Pair;
+
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Abstract utility class to convert SaProposal to/from PersistableBundle.
+ *
+ * @hide
+ */
+abstract class SaProposalUtilsBase {
+    static final String ENCRYPT_ALGO_KEY = "ENCRYPT_ALGO_KEY";
+    static final String INTEGRITY_ALGO_KEY = "INTEGRITY_ALGO_KEY";
+    static final String DH_GROUP_KEY = "DH_GROUP_KEY";
+
+    static class EncryptionAlgoKeyLenPair {
+        private static final String ALGO_KEY = "ALGO_KEY";
+        private static final String KEY_LEN_KEY = "KEY_LEN_KEY";
+
+        public final int encryptionAlgo;
+        public final int keyLen;
+
+        EncryptionAlgoKeyLenPair(int encryptionAlgo, int keyLen) {
+            this.encryptionAlgo = encryptionAlgo;
+            this.keyLen = keyLen;
+        }
+
+        EncryptionAlgoKeyLenPair(PersistableBundle in) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+
+            this.encryptionAlgo = in.getInt(ALGO_KEY);
+            this.keyLen = in.getInt(KEY_LEN_KEY);
+        }
+
+        public PersistableBundle toPersistableBundle() {
+            final PersistableBundle result = new PersistableBundle();
+
+            result.putInt(ALGO_KEY, encryptionAlgo);
+            result.putInt(KEY_LEN_KEY, keyLen);
+
+            return result;
+        }
+    }
+
+    /**
+     * Serializes common info of a SaProposal to a PersistableBundle.
+     *
+     * @hide
+     */
+    @NonNull
+    static PersistableBundle toPersistableBundle(SaProposal proposal) {
+        final PersistableBundle result = new PersistableBundle();
+
+        final List<EncryptionAlgoKeyLenPair> encryptAlgoKeyLenPairs = new ArrayList<>();
+        for (Pair<Integer, Integer> pair : proposal.getEncryptionAlgorithms()) {
+            encryptAlgoKeyLenPairs.add(new EncryptionAlgoKeyLenPair(pair.first, pair.second));
+        }
+        final PersistableBundle encryptionBundle =
+                PersistableBundleUtils.fromList(
+                        encryptAlgoKeyLenPairs, EncryptionAlgoKeyLenPair::toPersistableBundle);
+        result.putPersistableBundle(ENCRYPT_ALGO_KEY, encryptionBundle);
+
+        final int[] integrityAlgoIdArray =
+                proposal.getIntegrityAlgorithms().stream().mapToInt(i -> i).toArray();
+        result.putIntArray(INTEGRITY_ALGO_KEY, integrityAlgoIdArray);
+
+        final int[] dhGroupArray = proposal.getDhGroups().stream().mapToInt(i -> i).toArray();
+        result.putIntArray(DH_GROUP_KEY, dhGroupArray);
+
+        return result;
+    }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
new file mode 100644
index 0000000..e62acac
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest;
+import android.os.PersistableBundle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert TunnelModeChildSessionParams to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class TunnelModeChildSessionParamsUtils {
+    private static final String TAG = TunnelModeChildSessionParamsUtils.class.getSimpleName();
+
+    private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY";
+    private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY";
+    private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY";
+    private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY";
+    private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY";
+    private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY";
+
+    private static class ConfigRequest {
+        private static final int TYPE_IPV4_ADDRESS = 1;
+        private static final int TYPE_IPV6_ADDRESS = 2;
+        private static final int TYPE_IPV4_DNS = 3;
+        private static final int TYPE_IPV6_DNS = 4;
+        private static final int TYPE_IPV4_DHCP = 5;
+        private static final int TYPE_IPV4_NETMASK = 6;
+
+        private static final String TYPE_KEY = "type";
+        private static final String VALUE_KEY = "address";
+        private static final String IP6_PREFIX_LEN = "ip6PrefixLen";
+
+        private static final int PREFIX_LEN_UNUSED = -1;
+
+        public final int type;
+        public final int ip6PrefixLen;
+
+        // Null when it is an empty request
+        @Nullable public final InetAddress address;
+
+        ConfigRequest(TunnelModeChildConfigRequest config) {
+            int prefixLen = PREFIX_LEN_UNUSED;
+
+            if (config instanceof ConfigRequestIpv4Address) {
+                type = TYPE_IPV4_ADDRESS;
+                address = ((ConfigRequestIpv4Address) config).getAddress();
+            } else if (config instanceof ConfigRequestIpv6Address) {
+                type = TYPE_IPV6_ADDRESS;
+                address = ((ConfigRequestIpv6Address) config).getAddress();
+                if (address != null) {
+                    prefixLen = ((ConfigRequestIpv6Address) config).getPrefixLength();
+                }
+            } else if (config instanceof ConfigRequestIpv4DnsServer) {
+                type = TYPE_IPV4_DNS;
+                address = null;
+            } else if (config instanceof ConfigRequestIpv6DnsServer) {
+                type = TYPE_IPV6_DNS;
+                address = null;
+            } else if (config instanceof ConfigRequestIpv4DhcpServer) {
+                type = TYPE_IPV4_DHCP;
+                address = null;
+            } else if (config instanceof ConfigRequestIpv4Netmask) {
+                type = TYPE_IPV4_NETMASK;
+                address = null;
+            } else {
+                throw new IllegalStateException("Unknown TunnelModeChildConfigRequest");
+            }
+
+            ip6PrefixLen = prefixLen;
+        }
+
+        ConfigRequest(PersistableBundle in) {
+            Objects.requireNonNull(in, "PersistableBundle was null");
+
+            type = in.getInt(TYPE_KEY);
+            ip6PrefixLen = in.getInt(IP6_PREFIX_LEN);
+
+            String addressStr = in.getString(VALUE_KEY);
+            if (addressStr == null) {
+                address = null;
+            } else {
+                address = InetAddresses.parseNumericAddress(addressStr);
+            }
+        }
+
+        @NonNull
+        public PersistableBundle toPersistableBundle() {
+            final PersistableBundle result = new PersistableBundle();
+
+            result.putInt(TYPE_KEY, type);
+            result.putInt(IP6_PREFIX_LEN, ip6PrefixLen);
+
+            if (address != null) {
+                result.putString(VALUE_KEY, address.getHostAddress());
+            }
+
+            return result;
+        }
+    }
+
+    /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(
+            @NonNull TunnelModeChildSessionParams params) {
+        final PersistableBundle result = new PersistableBundle();
+
+        final PersistableBundle saProposalBundle =
+                PersistableBundleUtils.fromList(
+                        params.getSaProposals(), ChildSaProposalUtils::toPersistableBundle);
+        result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle);
+
+        final PersistableBundle inTsBundle =
+                PersistableBundleUtils.fromList(
+                        params.getInboundTrafficSelectors(),
+                        IkeTrafficSelectorUtils::toPersistableBundle);
+        result.putPersistableBundle(INBOUND_TS_KEY, inTsBundle);
+
+        final PersistableBundle outTsBundle =
+                PersistableBundleUtils.fromList(
+                        params.getOutboundTrafficSelectors(),
+                        IkeTrafficSelectorUtils::toPersistableBundle);
+        result.putPersistableBundle(OUTBOUND_TS_KEY, outTsBundle);
+
+        result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds());
+        result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds());
+
+        final List<ConfigRequest> reqList = new ArrayList<>();
+        for (TunnelModeChildConfigRequest req : params.getConfigurationRequests()) {
+            reqList.add(new ConfigRequest(req));
+        }
+        final PersistableBundle configReqListBundle =
+                PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle);
+        result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle);
+
+        return result;
+    }
+
+    private static List<IkeTrafficSelector> getTsFromPersistableBundle(
+            PersistableBundle in, String key) {
+        PersistableBundle tsBundle = in.getPersistableBundle(key);
+        Objects.requireNonNull(tsBundle, "Value for key " + key + " was null");
+        return PersistableBundleUtils.toList(
+                tsBundle, IkeTrafficSelectorUtils::fromPersistableBundle);
+    }
+
+    /** Constructs a TunnelModeChildSessionParams by deserializing a PersistableBundle. */
+    @NonNull
+    public static TunnelModeChildSessionParams fromPersistableBundle(
+            @NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        final TunnelModeChildSessionParams.Builder builder =
+                new TunnelModeChildSessionParams.Builder();
+
+        final PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY);
+        Objects.requireNonNull(proposalBundle, "SA proposal was null");
+        final List<ChildSaProposal> proposals =
+                PersistableBundleUtils.toList(
+                        proposalBundle, ChildSaProposalUtils::fromPersistableBundle);
+        for (ChildSaProposal p : proposals) {
+            builder.addSaProposal(p);
+        }
+
+        for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, INBOUND_TS_KEY)) {
+            builder.addInboundTrafficSelectors(ts);
+        }
+
+        for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, OUTBOUND_TS_KEY)) {
+            builder.addOutboundTrafficSelectors(ts);
+        }
+
+        builder.setLifetimeSeconds(
+                in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY));
+        final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY);
+        Objects.requireNonNull(configReqListBundle, "Config request list was null");
+        final List<ConfigRequest> reqList =
+                PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new);
+
+        boolean hasIpv4AddressReq = false;
+        boolean hasIpv4NetmaskReq = false;
+        for (ConfigRequest req : reqList) {
+            switch (req.type) {
+                case ConfigRequest.TYPE_IPV4_ADDRESS:
+                    hasIpv4AddressReq = true;
+                    if (req.address == null) {
+                        builder.addInternalAddressRequest(AF_INET);
+                    } else {
+                        builder.addInternalAddressRequest((Inet4Address) req.address);
+                    }
+                    break;
+                case ConfigRequest.TYPE_IPV6_ADDRESS:
+                    if (req.address == null) {
+                        builder.addInternalAddressRequest(AF_INET6);
+                    } else {
+                        builder.addInternalAddressRequest(
+                                (Inet6Address) req.address, req.ip6PrefixLen);
+                    }
+                    break;
+                case ConfigRequest.TYPE_IPV4_NETMASK:
+                    // Do not need to set netmask because it will be automatically set by the
+                    // builder when an IPv4 internal address request is set.
+                    hasIpv4NetmaskReq = true;
+                    break;
+                case ConfigRequest.TYPE_IPV4_DNS:
+                    if (req.address != null) {
+                        Log.w(TAG, "Requesting a specific IPv4 DNS server is unsupported");
+                    }
+                    builder.addInternalDnsServerRequest(AF_INET);
+                    break;
+                case ConfigRequest.TYPE_IPV6_DNS:
+                    if (req.address != null) {
+                        Log.w(TAG, "Requesting a specific IPv6 DNS server is unsupported");
+                    }
+                    builder.addInternalDnsServerRequest(AF_INET6);
+                    break;
+                case ConfigRequest.TYPE_IPV4_DHCP:
+                    if (req.address != null) {
+                        Log.w(TAG, "Requesting a specific IPv4 DHCP server is unsupported");
+                    }
+                    builder.addInternalDhcpServerRequest(AF_INET);
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unrecognized config request type: " + req.type);
+            }
+        }
+
+        if (hasIpv4AddressReq != hasIpv4NetmaskReq) {
+            Log.w(
+                    TAG,
+                    String.format(
+                            "Expect IPv4 address request and IPv4 netmask request either both"
+                                + " exist or both absent, but found hasIpv4AddressReq exists? %b,"
+                                + " hasIpv4AddressReq exists? %b, ",
+                            hasIpv4AddressReq, hasIpv4NetmaskReq));
+        }
+
+        return builder.build();
+    }
+}
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index 81c781b..a999e65 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -247,6 +247,7 @@
     /**
      * Get the SoundTrigger mode while in Battery Saver.
      */
+    @PowerManager.SoundTriggerPowerSaveMode
     public int getSoundTriggerMode() {
         return mSoundTriggerMode;
     }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 74df1b2..a5b0e8d 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1288,10 +1288,12 @@
     public static final String HOST = getString("ro.build.host");
 
     /**
-     * Returns true if we are running a debug build such as "user-debug" or "eng".
-     * @hide
+     * Returns true if the device is running a debuggable build such as "userdebug" or "eng".
+     *
+     * Debuggable builds allow users to gain root access via local shell, attach debuggers to any
+     * application regardless of whether they have the "debuggable" attribute set, or downgrade
+     * selinux into "permissive" mode in particular.
      */
-    @UnsupportedAppUsage
     public static final boolean IS_DEBUGGABLE =
             SystemProperties.getInt("ro.debuggable", 0) == 1;
 
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index c8e682c..e068772 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -76,7 +76,9 @@
      * A sequential vibration effect should be performed by multiple vibrators in order.
      *
      * @see CombinedVibrationEffect.SequentialCombination
+     * @hide
      */
+    @TestApi
     @NonNull
     public static SequentialCombination startSequential() {
         return new SequentialCombination();
@@ -162,7 +164,9 @@
      * A combination of haptic effects that should be played in multiple vibrators in sequence.
      *
      * @see CombinedVibrationEffect#startSequential()
+     * @hide
      */
+    @TestApi
     public static final class SequentialCombination {
 
         private final ArrayList<CombinedVibrationEffect> mEffects = new ArrayList<>();
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 874add5..91d6a9b 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -23,7 +23,6 @@
 import android.net.Network;
 import android.net.NetworkStats;
 import android.net.RouteInfo;
-import android.net.UidRange;
 
 /**
  * @hide
@@ -182,11 +181,6 @@
     String[] listTetheredInterfaces();
 
     /**
-     * Sets the list of DNS forwarders (in order of priority)
-     */
-    void setDnsForwarders(in Network network, in String[] dns);
-
-    /**
      * Returns the list of DNS forwarders (in order of priority)
      */
     String[] getDnsForwarders();
@@ -300,8 +294,6 @@
     void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
     void setFirewallChainEnabled(int chain, boolean enable);
 
-    void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
-
     /**
      * Allow UID to call protect().
      */
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0587610..03e5f1d 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -503,6 +503,20 @@
     }
 
     /** @hide */
+    public static String effectStrengthToString(int effectStrength) {
+        switch (effectStrength) {
+            case EFFECT_STRENGTH_LIGHT:
+                return "LIGHT";
+            case EFFECT_STRENGTH_MEDIUM:
+                return "MEDIUM";
+            case EFFECT_STRENGTH_STRONG:
+                return "STRONG";
+            default:
+                return Integer.toString(effectStrength);
+        }
+    }
+
+    /** @hide */
     @TestApi
     public static class OneShot extends VibrationEffect implements Parcelable {
         private final long mDuration;
@@ -936,8 +950,8 @@
 
         @Override
         public String toString() {
-            return "Prebaked{mEffectId=" + mEffectId
-                + ", mEffectStrength=" + mEffectStrength
+            return "Prebaked{mEffectId=" + effectIdToString(mEffectId)
+                + ", mEffectStrength=" + effectStrengthToString(mEffectStrength)
                 + ", mFallback=" + mFallback
                 + ", mFallbackEffect=" + mFallbackEffect
                 + "}";
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 07272e7..50d2de3 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.vibrator.IVibrator;
 import android.util.SparseBooleanArray;
 
 import java.util.ArrayList;
@@ -33,20 +34,7 @@
  * @hide
  */
 public final class VibratorInfo implements Parcelable {
-
-    /**
-     * Capability to set amplitude values to vibrations.
-     * @hide
-     */
-    // Internally this maps to the HAL constant IVibrator::CAP_AMPLITUDE_CONTROL
-    public static final int CAPABILITY_AMPLITUDE_CONTROL = 4;
-
-    /**
-     * Capability to compose primitives into a single effect.
-     * @hide
-     */
-    // Internally this maps to the HAL constant IVibrator::CAP_COMPOSE_EFFECTS
-    public static final int CAPABILITY_COMPOSE_EFFECTS = 32;
+    private static final String TAG = "VibratorInfo";
 
     private final int mId;
     private final long mCapabilities;
@@ -108,7 +96,7 @@
         return "VibratorInfo{"
                 + "mId=" + mId
                 + ", mCapabilities=" + Arrays.toString(getCapabilitiesNames())
-                + ", mCapabilities flags=" + mCapabilities
+                + ", mCapabilities flags=" + Long.toBinaryString(mCapabilities)
                 + ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames())
                 + ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames())
                 + '}';
@@ -125,7 +113,7 @@
      * @return True if the hardware can control the amplitude of the vibrations, otherwise false.
      */
     public boolean hasAmplitudeControl() {
-        return hasCapability(CAPABILITY_AMPLITUDE_CONTROL);
+        return hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL);
     }
 
     /**
@@ -153,7 +141,7 @@
      * @return Whether the primitive is supported.
      */
     public boolean isPrimitiveSupported(@VibrationEffect.Composition.Primitive int primitiveId) {
-        return hasCapability(CAPABILITY_COMPOSE_EFFECTS) && mSupportedPrimitives != null
+        return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null
                 && mSupportedPrimitives.get(primitiveId, false);
     }
 
@@ -170,11 +158,26 @@
 
     private String[] getCapabilitiesNames() {
         List<String> names = new ArrayList<>();
-        if (hasCapability(CAPABILITY_AMPLITUDE_CONTROL)) {
+        if (hasCapability(IVibrator.CAP_ON_CALLBACK)) {
+            names.add("ON_CALLBACK");
+        }
+        if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) {
+            names.add("PERFORM_CALLBACK");
+        }
+        if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+            names.add("COMPOSE_EFFECTS");
+        }
+        if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+            names.add("ALWAYS_ON_CONTROL");
+        }
+        if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
             names.add("AMPLITUDE_CONTROL");
         }
-        if (hasCapability(CAPABILITY_COMPOSE_EFFECTS)) {
-            names.add("COMPOSE_EFFECTS");
+        if (hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+            names.add("EXTERNAL_CONTROL");
+        }
+        if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
+            names.add("EXTERNAL_AMPLITUDE_CONTROL");
         }
         return names.toArray(new String[names.size()]);
     }
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 592e98a..87dced8 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -155,22 +155,21 @@
     }
 
     /**
-     * Set up an app's code path. The expected outcome of this method is:
+     * Link an app's files from the stage dir to the final installation location.
+     * The expected outcome of this method is:
      * 1) The actual apk directory under /data/incremental is bind-mounted to the parent directory
      * of {@code afterCodeFile}.
      * 2) All the files under {@code beforeCodeFile} will show up under {@code afterCodeFile}.
      *
      * @param beforeCodeFile Path that is currently bind-mounted and have APKs under it.
-     *                       Should no longer have any APKs after this method is called.
      *                       Example: /data/app/vmdl*tmp
      * @param afterCodeFile Path that should will have APKs after this method is called. Its parent
      *                      directory should be bind-mounted to a directory under /data/incremental.
      *                      Example: /data/app/~~[randomStringA]/[packageName]-[randomStringB]
      * @throws IllegalArgumentException
      * @throws IOException
-     * TODO(b/147371381): add unit tests
      */
-    public void renameCodePath(File beforeCodeFile, File afterCodeFile)
+    public void linkCodePath(File beforeCodeFile, File afterCodeFile)
             throws IllegalArgumentException, IOException {
         final File beforeCodeAbsolute = beforeCodeFile.getAbsoluteFile();
         final IncrementalStorage apkStorage = openStorage(beforeCodeAbsolute.toString());
@@ -188,7 +187,6 @@
         try {
             final String afterCodePathName = afterCodeFile.getName();
             linkFiles(apkStorage, beforeCodeAbsolute, "", linkedApkStorage, afterCodePathName);
-            apkStorage.unBind(beforeCodeAbsolute.toString());
         } catch (Exception e) {
             linkedApkStorage.unBind(targetStorageDir);
             throw e;
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 0041699..98b4e0b 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -28,6 +28,8 @@
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import com.android.internal.os.AppFuseMount;
+import android.app.PendingIntent;
+
 
 /**
  * WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -198,4 +200,5 @@
     void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
     void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91;
     void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92;
+    PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 93;
     }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 7c8874c..c967deb 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -49,6 +49,7 @@
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.PendingIntent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -701,6 +702,33 @@
         }
     }
 
+    /**
+     * Returns a {@link PendingIntent} that can be used by Apps with
+     * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission
+     * to launch the manageSpaceActivity for any App that implements it, irrespective of its
+     * exported status.
+     * <p>
+     * Caller has the responsibility of supplying a valid packageName which has
+     * manageSpaceActivity implemented.
+     *
+     * @param packageName package name for the App for which manageSpaceActivity is to be launched
+     * @param requestCode for launching the activity
+     * @return PendingIntent to launch the manageSpaceActivity if successful, null if the
+     * packageName doesn't have a manageSpaceActivity.
+     * @throws IllegalArgumentException an invalid packageName is supplied.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
+    @Nullable
+    public PendingIntent getManageSpaceActivityIntent(
+            @NonNull String packageName, int requestCode) {
+        try {
+            return mStorageManager.getManageSpaceActivityIntent(packageName,
+                    requestCode);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private ObbInfo getObbInfo(String canonicalPath) {
         try {
             final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath);
@@ -2738,10 +2766,11 @@
      * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public void notifyAppIoBlocked(@NonNull String volumeUuid, int uid, int tid,
+    public void notifyAppIoBlocked(@NonNull UUID volumeUuid, int uid, int tid,
             @AppIoBlockedReason int reason) {
+        Objects.requireNonNull(volumeUuid);
         try {
-            mStorageManager.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+            mStorageManager.notifyAppIoBlocked(convert(volumeUuid), uid, tid, reason);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2764,10 +2793,11 @@
      * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public void notifyAppIoResumed(@NonNull String volumeUuid, int uid, int tid,
+    public void notifyAppIoResumed(@NonNull UUID volumeUuid, int uid, int tid,
             @AppIoBlockedReason int reason) {
+        Objects.requireNonNull(volumeUuid);
         try {
-            mStorageManager.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+            mStorageManager.notifyAppIoResumed(convert(volumeUuid), uid, tid, reason);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index b12bb2e..396ba2d 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.os.IVold;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -112,4 +113,10 @@
      * @param bytes number of bytes which need to be freed
      */
     public abstract void freeCache(@Nullable String volumeUuid, long bytes);
+
+    /**
+     * Returns the {@link VolumeInfo#getId()} values for the volumes matching
+     * {@link VolumeInfo#isPrimary()}
+     */
+    public abstract List<String> getPrimaryVolumeIds();
 }
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index b323468..19a3a8b 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,7 +1,13 @@
 # Bug component: 137825
 
+eugenesusla@google.com
 evanseverson@google.com
+evanxinchen@google.com
+ewol@google.com
+guojing@google.com
+jaysullivan@google.com
 ntmyren@google.com
-zhanghai@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
+theianchen@google.com
+zhanghai@google.com
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 084b18e..913b827 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -668,7 +668,7 @@
     public void getPrivilegesDescriptionStringForProfile(
             @NonNull String profileName,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull Consumer<String> callback) {
+            @NonNull Consumer<CharSequence> callback) {
         mRemoteService.postAsync(service -> {
             AndroidFuture<String> future = new AndroidFuture<>();
             service.getPrivilegesDescriptionStringForProfile(profileName, future);
diff --git a/core/java/android/permissionpresenterservice/OWNERS b/core/java/android/permissionpresenterservice/OWNERS
index b323468..fb6099c 100644
--- a/core/java/android/permissionpresenterservice/OWNERS
+++ b/core/java/android/permissionpresenterservice/OWNERS
@@ -1,7 +1,3 @@
 # Bug component: 137825
 
-evanseverson@google.com
-ntmyren@google.com
-zhanghai@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6e89faf..e9bbcc79 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -505,6 +505,22 @@
             "connectivity_thermal_power_manager";
 
     /**
+     * Namespace for all statsd java features that can be applied immediately.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_STATSD_JAVA = "statsd_java";
+
+    /**
+     * Namespace for all statsd java features that are applied on boot.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot";
+
+    /**
      * Namespace for all statsd native features that can be applied immediately.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 09d0af1..85cef84 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10512,18 +10512,6 @@
                 "force_desktop_mode_on_external_displays";
 
         /**
-         * Whether to allow non-resizable apps to be freeform.
-         *
-         * TODO(b/176061101) remove after update all usages
-         * @deprecated use {@link #DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}
-         * @hide
-         */
-        @Deprecated
-        @Readable
-        public static final String DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM =
-                "enable_sizecompat_freeform";
-
-        /**
          * Whether to allow non-resizable apps to be shown in multi-window. The app will be
          * letterboxed if the request orientation is not met, and will be shown in size-compat
          * mode if the container size has changed.
@@ -16576,30 +16564,6 @@
 
     /**
      * Performs a strict and comprehensive check of whether a calling package is allowed to
-     * change the state of network, as the condition differs for pre-M, M+, and
-     * privileged/preinstalled apps. The caller is expected to have either the
-     * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
-     * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
-     * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
-     * permission and cannot be revoked. See http://b/23597341
-     *
-     * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
-     * of this app will be updated to the current time.
-     * @hide
-     */
-    public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid,
-            String callingPackage, String callingAttributionTag, boolean throwException) {
-        if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
-                == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
-                callingPackage, callingAttributionTag, throwException,
-                AppOpsManager.OP_WRITE_SETTINGS, PM_CHANGE_NETWORK_STATE, true);
-    }
-
-    /**
-     * Performs a strict and comprehensive check of whether a calling package is allowed to
      * draw on top of other apps, as the conditions differs for pre-M, M+, and
      * privileged/preinstalled apps. If the provided uid does not match the callingPackage,
      * a negative result will be returned.
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 7996f09..8a4812a 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5302,5 +5302,13 @@
          * @hide
          */
         public static final String COLUMN_RCS_CONFIG = "rcs_config";
+
+        /**
+         * TelephonyProvider column name for VoIMS provisioning. Default is 0.
+         * <P>Type: INTEGER </P>
+         *
+         * @hide
+         */
+        public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status";
     }
 }
diff --git a/core/java/android/service/storage/ExternalStorageService.java b/core/java/android/service/storage/ExternalStorageService.java
index 87add57..bbe184b 100644
--- a/core/java/android/service/storage/ExternalStorageService.java
+++ b/core/java/android/service/storage/ExternalStorageService.java
@@ -102,14 +102,6 @@
      */
     public static final String EXTRA_PACKAGE_NAME = "android.service.storage.extra.package_name";
 
-    /**
-     * {@link Bundle} key for a {@link Long} value.
-     *
-     * {@hide}
-     */
-    public static final String EXTRA_ANR_TIMEOUT_MS =
-            "android.service.storage.extra.anr_timeout_ms";
-
     /** @hide */
     @IntDef(flag = true, prefix = {"FLAG_SESSION_"},
         value = {FLAG_SESSION_TYPE_FUSE, FLAG_SESSION_ATTRIBUTE_INDEXABLE})
@@ -178,12 +170,12 @@
     }
 
     /**
-     * Called when {@code packageName} is about to ANR
+     * Called when {@code packageName} is about to ANR. The {@link ExternalStorageService} can
+     * show a progress dialog for the {@code reason}.
      *
-     * @return ANR dialog delay in milliseconds
      */
-    public long onGetAnrDelayMillis(@NonNull String packageName, int uid) {
-        throw new UnsupportedOperationException("onGetAnrDelayMillis not implemented");
+    public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, int reason) {
+        throw new UnsupportedOperationException("onAnrDelayStarted not implemented");
     }
 
     @Override
@@ -247,14 +239,13 @@
         }
 
         @Override
-        public void getAnrDelayMillis(String packageName, int uid, RemoteCallback callback)
+        public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
                 throws RemoteException {
             mHandler.post(() -> {
                 try {
-                    long timeoutMs = onGetAnrDelayMillis(packageName, uid);
-                    sendTimeoutResult(packageName, timeoutMs, null /* throwable */, callback);
+                    onAnrDelayStarted(packageName, uid, tid, reason);
                 } catch (Throwable t) {
-                    sendTimeoutResult(packageName, 0 /* timeoutMs */, t, callback);
+                    // Ignored
                 }
             });
         }
@@ -267,16 +258,5 @@
             }
             callback.sendResult(bundle);
         }
-
-        private void sendTimeoutResult(String packageName, long timeoutMs, Throwable throwable,
-                RemoteCallback callback) {
-            Bundle bundle = new Bundle();
-            bundle.putString(EXTRA_PACKAGE_NAME, packageName);
-            bundle.putLong(EXTRA_ANR_TIMEOUT_MS, timeoutMs);
-            if (throwable != null) {
-                bundle.putParcelable(EXTRA_ERROR, new ParcelableException(throwable));
-            }
-            callback.sendResult(bundle);
-        }
     }
 }
diff --git a/core/java/android/service/storage/IExternalStorageService.aidl b/core/java/android/service/storage/IExternalStorageService.aidl
index 2e0bd86..0766b75 100644
--- a/core/java/android/service/storage/IExternalStorageService.aidl
+++ b/core/java/android/service/storage/IExternalStorageService.aidl
@@ -32,5 +32,5 @@
         in RemoteCallback callback);
     void freeCache(@utf8InCpp String sessionId, in String volumeUuid, long bytes,
         in RemoteCallback callback);
-    void getAnrDelayMillis(String packageName, int uid, in RemoteCallback callback);
+    void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason);
 }
\ No newline at end of file
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 3c35d2c..7f1c5ff 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -19,15 +19,18 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.CallSuper;
+import android.annotation.DurationMillisLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
+import android.media.AudioFormat;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -57,14 +60,21 @@
 
     private final IHotwordDetectionService mInterface = new IHotwordDetectionService.Stub() {
         @Override
-        public void detectFromDspSource(int sessionId, IDspHotwordDetectionCallback callback)
+        public void detectFromDspSource(
+                ParcelFileDescriptor audioStream,
+                AudioFormat audioFormat,
+                long timeoutMillis,
+                IDspHotwordDetectionCallback callback)
                 throws RemoteException {
             if (DBG) {
                 Log.d(TAG, "#detectFromDspSource");
             }
             mHandler.sendMessage(obtainMessage(HotwordDetectionService::onDetectFromDspSource,
                     HotwordDetectionService.this,
-                    sessionId, new DspHotwordDetectionCallback(callback)));
+                    audioStream,
+                    audioFormat,
+                    timeoutMillis,
+                    new DspHotwordDetectionCallback(callback)));
         }
     };
 
@@ -89,15 +99,24 @@
     /**
      * Detect the audio data generated from Dsp.
      *
-     * @param sessionId The session to use when attempting to capture more audio from the DSP
-     *                  hardware.
+     * <p>Note: the clients are supposed to call {@code close} on the input stream when they are
+     * done with the operation in order to free up resources.
+     *
+     * @param audioStream Stream containing audio bytes returned from DSP
+     * @param audioFormat Format of the supplied audio
+     * @param timeoutMillis Timeout in milliseconds for the operation to invoke the callback. If
+     *                      the application fails to abide by the timeout, system will close the
+     *                      microphone and cancel the operation.
      * @param callback Use {@link HotwordDetectionService#DspHotwordDetectionCallback} to return
      * the detected result.
      *
      * @hide
      */
     @SystemApi
-    public void onDetectFromDspSource(int sessionId,
+    public void onDetectFromDspSource(
+            @NonNull ParcelFileDescriptor audioStream,
+            @NonNull AudioFormat audioFormat,
+            @DurationMillisLong long timeoutMillis,
             @NonNull DspHotwordDetectionCallback callback) {
     }
 
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index 990ad45..cbe76e4 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -16,6 +16,8 @@
 
 package android.service.voice;
 
+import android.media.AudioFormat;
+import android.os.ParcelFileDescriptor;
 import android.service.voice.IDspHotwordDetectionCallback;
 
 /**
@@ -24,5 +26,9 @@
  * @hide
  */
 oneway interface IHotwordDetectionService {
-    void detectFromDspSource(int sessionId, in IDspHotwordDetectionCallback callback);
+    void detectFromDspSource(
+    in ParcelFileDescriptor audioStream,
+    in AudioFormat audioFormat,
+    long timeoutMillis,
+    in IDspHotwordDetectionCallback callback);
 }
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 14aa386..5425c21 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -2,5 +2,7 @@
 per-file FeatureFlagUtils.java = tmfang@google.com
 per-file FeatureFlagUtils.java = asapperstein@google.com
 
-per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
 per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS
+per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
+
+per-file PackageUtils.java = file:/core/java/android/content/pm/OWNERS
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 6718e93..05c86172 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -510,10 +510,12 @@
     }
 
     /**
+     * Compares the contents of this {@link SparseArray} to the specified {@link SparseArray}.
+     *
      * For backwards compatibility reasons, {@link Object#equals(Object)} cannot be implemented,
      * so this serves as a manually invoked alternative.
      */
-    public boolean contentEquals(@Nullable SparseArray<E> other) {
+    public boolean contentEquals(@Nullable SparseArray<?> other) {
         if (other == null) {
             return false;
         }
@@ -534,6 +536,9 @@
     }
 
     /**
+     * Returns a hash code value for the contents of this {@link SparseArray}, combining the
+     * {@link Objects#hashCode(Object)} result of all its keys and values.
+     *
      * For backwards compatibility, {@link Object#hashCode()} cannot be implemented, so this serves
      * as a manually invoked alternative.
      */
diff --git a/core/java/android/util/apk/OWNERS b/core/java/android/util/apk/OWNERS
new file mode 100644
index 0000000..52c9550
--- /dev/null
+++ b/core/java/android/util/apk/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/pm/OWNERS
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 9473845..09452828 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -383,7 +383,8 @@
         final List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
         infos.clear();
         try {
-            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null
+                    || viewId == null) {
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
diff --git a/core/java/android/view/AppTransitionAnimationSpec.java b/core/java/android/view/AppTransitionAnimationSpec.java
index 877bb56..3215f2b 100644
--- a/core/java/android/view/AppTransitionAnimationSpec.java
+++ b/core/java/android/view/AppTransitionAnimationSpec.java
@@ -28,8 +28,8 @@
 
     public AppTransitionAnimationSpec(Parcel in) {
         taskId = in.readInt();
-        rect = in.readParcelable(null);
-        buffer = in.readParcelable(null);
+        rect = in.readTypedObject(Rect.CREATOR);
+        buffer = in.readTypedObject(HardwareBuffer.CREATOR);
     }
 
     @Override
@@ -40,8 +40,8 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(taskId);
-        dest.writeParcelable(rect, 0 /* flags */);
-        dest.writeParcelable(buffer, 0);
+        dest.writeTypedObject(rect, 0 /* flags */);
+        dest.writeTypedObject(buffer, 0 /* flags */);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<AppTransitionAnimationSpec> CREATOR
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
new file mode 100644
index 0000000..5a1b850
--- /dev/null
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.function.Consumer;
+
+/**
+ * Class that holds all registered {@link CrossWindowBlurEnabledListener}s. It listens
+ * for updates from the WindowManagerService and updates all registered listeners.
+ * @hide
+ */
+public final class CrossWindowBlurListeners {
+    private static final String TAG = "CrossWindowBlurListeners";
+
+    // property for background blur support in surface flinger
+    private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
+    public static final boolean CROSS_WINDOW_BLUR_SUPPORTED =
+            SystemProperties.get(BLUR_PROPERTY, "default").equals("1");
+
+    private static volatile CrossWindowBlurListeners sInstance;
+    private static final Object sLock = new Object();
+
+    private final BlurEnabledListenerInternal mListenerInternal = new BlurEnabledListenerInternal();
+    private final ArraySet<Consumer<Boolean>> mListeners = new ArraySet();
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private boolean mInternalListenerAttached = false;
+    private boolean mCrossWindowBlurEnabled;
+
+    private CrossWindowBlurListeners() {}
+
+    /**
+     * Returns a CrossWindowBlurListeners instance
+     */
+    public static CrossWindowBlurListeners getInstance() {
+        CrossWindowBlurListeners instance = sInstance;
+        if (instance == null) {
+
+            synchronized (sLock) {
+                instance = sInstance;
+                if (instance == null) {
+                    instance = new CrossWindowBlurListeners();
+                    sInstance = instance;
+                }
+            }
+        }
+        return instance;
+    }
+
+    boolean isCrossWindowBlurEnabled() {
+        synchronized (sLock) {
+            attachInternalListenerIfNeededLocked();
+            return mCrossWindowBlurEnabled;
+        }
+    }
+
+    void addListener(Consumer<Boolean> listener) {
+        if (listener == null) return;
+
+        synchronized (sLock) {
+            attachInternalListenerIfNeededLocked();
+
+            mListeners.add(listener);
+            notifyListenerOnMain(listener, mCrossWindowBlurEnabled);
+        }
+    }
+
+
+    void removeListener(Consumer<Boolean> listener) {
+        if (listener == null) return;
+
+        synchronized (sLock) {
+            mListeners.remove(listener);
+
+            if (mInternalListenerAttached && mListeners.size() == 0) {
+                try {
+                    WindowManagerGlobal.getWindowManagerService()
+                            .unregisterCrossWindowBlurEnabledListener(mListenerInternal);
+                    mInternalListenerAttached = false;
+                } catch (RemoteException e) {
+                    Log.d(TAG, "Could not unregister ICrossWindowBlurEnabledListener");
+                }
+            }
+        }
+    }
+
+    private void attachInternalListenerIfNeededLocked() {
+        if (!mInternalListenerAttached) {
+            try {
+                mCrossWindowBlurEnabled = WindowManagerGlobal.getWindowManagerService()
+                        .registerCrossWindowBlurEnabledListener(mListenerInternal);
+                mInternalListenerAttached = true;
+            } catch (RemoteException e) {
+                Log.d(TAG, "Could not register ICrossWindowBlurEnabledListener");
+            }
+        }
+    }
+
+    private void notifyListenerOnMain(Consumer<Boolean> listener, boolean enabled) {
+        mMainHandler.post(() -> {
+            listener.accept(enabled);
+        });
+    }
+
+    private final class BlurEnabledListenerInternal extends ICrossWindowBlurEnabledListener.Stub {
+        @Override
+        public void onCrossWindowBlurEnabledChanged(boolean enabled) {
+            synchronized (sLock) {
+                mCrossWindowBlurEnabled = enabled;
+
+                for (int i = 0; i < mListeners.size(); i++) {
+                    notifyListenerOnMain(mListeners.valueAt(i), enabled);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0ba1dfe..8117c96 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -34,6 +34,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.display.DeviceProductInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
@@ -1181,6 +1182,18 @@
     }
 
     /**
+     * Returns the product-specific information about the display or the directly connected
+     * device on the display chain.
+     * For example, if the display is transitively connected, this field may contain product
+     * information about the intermediate device.
+     * Returns {@code null} if product information is not available.
+     */
+    @Nullable
+    public DeviceProductInfo getDeviceProductInfo() {
+        return mDisplayInfo.deviceProductInfo;
+    }
+
+    /**
      * Gets display metrics that describe the size and density of this display.
      * The size returned by this method does not necessarily represent the
      * actual raw size (native resolution) of the display.
diff --git a/core/java/android/view/ICrossWindowBlurEnabledListener.aidl b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl
new file mode 100644
index 0000000..69286e2
--- /dev/null
+++ b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Listener to be invoked when cross-window blur is enabled or disabled.
+ * {@hide}
+ */
+oneway interface ICrossWindowBlurEnabledListener {
+    /**
+     * Method that will be invoked when cross-window blur is enabled or disabled.
+     * @param enabled True if cross-window blur is enabled.
+     */
+    void onCrossWindowBlurEnabledChanged(boolean enabled);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index afdf798..5477800 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,6 +35,7 @@
 import android.view.DisplayCutout;
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.ICrossWindowBlurEnabledListener;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IDisplayWindowListener;
 import android.view.IDisplayFoldListener;
@@ -730,7 +731,7 @@
     void showGlobalActions();
 
     /**
-     * Sets layer tracing flags for SurfaceFlingerTrace. 
+     * Sets layer tracing flags for SurfaceFlingerTrace.
      *
      * @param flags see definition in SurfaceTracing.cpp
      */
@@ -799,4 +800,20 @@
      * @param clientToken the window context's token
      */
     void unregisterWindowContextListener(IBinder clientToken);
+
+    /**
+     * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled.
+     *
+     * @param listener the listener to be registered
+     * @return true if cross-window blur is currently enabled; false otherwise
+     */
+    boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
+
+    /**
+     * Unregisters a listener which was registered with
+     * {@link #registerCrossWindowBlurEnabledListener()}.
+     *
+     * @param listener the listener to be unregistered
+     */
+    void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
 }
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 4a5c95f..d23a1e5 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -116,8 +116,9 @@
         if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) {
             return;
         }
+        View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
         if (DEBUG) {
-            Log.v(TAG, "onWindowFocus: " + focusedView
+            Log.v(TAG, "onWindowFocus: " + viewForWindowFocus
                     + " softInputMode=" + InputMethodDebug.softInputModeToString(
                     windowAttribute.softInputMode));
         }
@@ -128,8 +129,8 @@
             if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true");
             forceFocus = true;
         }
+
         // Update mNextServedView when focusedView changed.
-        final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
         onViewFocusChanged(viewForWindowFocus, true);
 
         // Starting new input when the next focused view is same as served view but the currently
diff --git a/core/java/android/view/InputEventAssigner.java b/core/java/android/view/InputEventAssigner.java
new file mode 100644
index 0000000..c159a12
--- /dev/null
+++ b/core/java/android/view/InputEventAssigner.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
+import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+
+/**
+ * Process input events and assign input event id to a specific frame.
+ *
+ * The assigned input event id is determined by where the current gesture is relative to the vsync.
+ * In the middle of the gesture (we already processed some input events, and already received at
+ * least 1 vsync), the latest InputEvent is assigned to the next frame.
+ * If a gesture just started, then the ACTION_DOWN event will be assigned to the next frame.
+ *
+ * Consider the following sequence:
+ * DOWN -> VSYNC 1 -> MOVE 1 -> MOVE 2 -> VSYNC 2.
+ *
+ * For VSYNC 1, we will assign the "DOWN" input event.
+ * For VSYNC 2, we will assign the "MOVE 2" input event.
+ *
+ * Consider another sequence:
+ * DOWN -> MOVE 1 -> MOVE 2 -> VSYNC 1 -> MOVE 3 -> VSYNC 2.
+ *
+ * For VSYNC 1, we will still assign the "DOWN" input event. That means that "MOVE 1" and "MOVE 2"
+ * events are not attributed to any frame.
+ * For VSYNC 2, the "MOVE 3" input event will be assigned.
+ *
+ * @hide
+ */
+public class InputEventAssigner {
+    private static final String TAG = "InputEventAssigner";
+    private boolean mHasUnprocessedDown = false;
+    private int mEventId = INVALID_INPUT_EVENT_ID;
+
+    /**
+     * Notify InputEventAssigner that the Choreographer callback has been processed. This will reset
+     * the 'down' state to assign the latest input event to the current frame.
+     */
+    public void onChoreographerCallback() {
+        // Mark completion of this frame. Use newest input event from now on.
+        mHasUnprocessedDown = false;
+    }
+
+    /**
+     * Process the provided input event to determine which event id to assign to the current frame.
+     * @param event the input event currently being processed
+     * @return the id of the input event to use for the current frame
+     */
+    public int processEvent(InputEvent event) {
+        if (event instanceof KeyEvent) {
+            // We will not do any special handling for key events
+            return event.getId();
+        }
+
+        if (event instanceof MotionEvent) {
+            MotionEvent motionEvent = (MotionEvent) event;
+            final int action = motionEvent.getActionMasked();
+
+            if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+                mHasUnprocessedDown = false;
+            }
+            if (motionEvent.isFromSource(SOURCE_TOUCHSCREEN) && action == MotionEvent.ACTION_DOWN) {
+                mHasUnprocessedDown = true;
+                mEventId = event.getId();
+                // This will remain 'true' even if we receive a MOVE event, as long as choreographer
+                // hasn't invoked the 'CALLBACK_INPUT' callback.
+            }
+            // Don't update the event id if we haven't processed DOWN yet.
+            if (!mHasUnprocessedDown) {
+                mEventId = event.getId();
+            }
+            return mEventId;
+        }
+
+        throw new IllegalArgumentException("Received unexpected " + event);
+    }
+}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index d67439c..6801c27 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3589,6 +3589,7 @@
             msg.append(", deviceId=").append(getDeviceId());
             msg.append(", source=0x").append(Integer.toHexString(getSource()));
             msg.append(", displayId=").append(getDisplayId());
+            msg.append(", eventId=").append(getId());
         }
         msg.append(" }");
         return msg.toString();
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 5ce4c50..6c8753b 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -27,7 +27,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
@@ -42,7 +42,7 @@
  * @hide
  */
 @RemoteViews.RemoteView
-public class NotificationHeaderView extends FrameLayout {
+public class NotificationHeaderView extends RelativeLayout {
     private final int mHeadingEndMargin;
     private final int mTouchableHeight;
     private OnClickListener mExpandClickListener;
@@ -159,7 +159,7 @@
      * @param extraMarginEnd extra margin in px
      */
     public void setTopLineExtraMarginEnd(int extraMarginEnd) {
-        mTopLineView.setHeaderTextMarginEnd(extraMarginEnd + mHeadingEndMargin);
+        mTopLineView.setHeaderTextMarginEnd(extraMarginEnd);
     }
 
     /**
@@ -181,12 +181,15 @@
      * @return extra margin
      */
     public int getTopLineExtraMarginEnd() {
-        return mTopLineView.getHeaderTextMarginEnd() - mHeadingEndMargin;
+        return mTopLineView.getHeaderTextMarginEnd();
     }
 
     /**
      * Get the base margin at the end of the top line view.
      * Add this to {@link #getTopLineExtraMarginEnd()} to get the total margin of the top line.
+     * <p>
+     * NOTE: This method's result is only valid if the expander does not have a number. Currently
+     * only groups headers and conversations have numbers, so this is safe to use by MediaStyle.
      *
      * @return base margin
      */
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index e66b17a..cbb86de 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -57,6 +57,7 @@
 per-file ViewRootImpl.java = file:/services/core/java/com/android/server/input/OWNERS
 per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS
+per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS
 
 # WindowManager
 per-file DisplayCutout.aidl = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index a5ff19e..ea97995 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -184,13 +184,13 @@
         }
 
         private RemoteAnimationAdapterEntry(Parcel in) {
-            adapter = in.readParcelable(RemoteAnimationAdapter.class.getClassLoader());
+            adapter = in.readTypedObject(RemoteAnimationAdapter.CREATOR);
             activityTypeFilter = in.readInt();
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeParcelable(adapter, flags);
+            dest.writeTypedObject(adapter, flags);
             dest.writeInt(activityTypeFilter);
         }
 
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 258a72c..ff84aa5 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -31,6 +31,7 @@
 import static android.view.RemoteAnimationTargetProto.START_LEASH;
 import static android.view.RemoteAnimationTargetProto.TASK_ID;
 import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 
 import android.annotation.IntDef;
 import android.app.PictureInPictureParams;
@@ -195,12 +196,30 @@
      */
     public PictureInPictureParams pictureInPictureParams;
 
+    /**
+     * The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used
+     * for non-app window.
+     */
+    public final @WindowManager.LayoutParams.WindowType int windowType;
+
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
             Rect localBounds, Rect screenSpaceBounds,
             WindowConfiguration windowConfig, boolean isNotInRecents,
             SurfaceControl startLeash, Rect startBounds,
             PictureInPictureParams pictureInPictureParams) {
+        this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
+                position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
+                startBounds, pictureInPictureParams, INVALID_WINDOW_TYPE);
+    }
+
+    public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
+            Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
+            Rect localBounds, Rect screenSpaceBounds,
+            WindowConfiguration windowConfig, boolean isNotInRecents,
+            SurfaceControl startLeash, Rect startBounds,
+            PictureInPictureParams pictureInPictureParams,
+            @WindowManager.LayoutParams.WindowType int windowType) {
         this.mode = mode;
         this.taskId = taskId;
         this.leash = leash;
@@ -217,25 +236,27 @@
         this.startLeash = startLeash;
         this.startBounds = startBounds == null ? null : new Rect(startBounds);
         this.pictureInPictureParams = pictureInPictureParams;
+        this.windowType = windowType;
     }
 
     public RemoteAnimationTarget(Parcel in) {
         taskId = in.readInt();
         mode = in.readInt();
-        leash = in.readParcelable(null);
+        leash = in.readTypedObject(SurfaceControl.CREATOR);
         isTranslucent = in.readBoolean();
-        clipRect = in.readParcelable(null);
-        contentInsets = in.readParcelable(null);
+        clipRect = in.readTypedObject(Rect.CREATOR);
+        contentInsets = in.readTypedObject(Rect.CREATOR);
         prefixOrderIndex = in.readInt();
-        position = in.readParcelable(null);
-        localBounds = in.readParcelable(null);
-        sourceContainerBounds = in.readParcelable(null);
-        screenSpaceBounds = in.readParcelable(null);
-        windowConfiguration = in.readParcelable(null);
+        position = in.readTypedObject(Point.CREATOR);
+        localBounds = in.readTypedObject(Rect.CREATOR);
+        sourceContainerBounds = in.readTypedObject(Rect.CREATOR);
+        screenSpaceBounds = in.readTypedObject(Rect.CREATOR);
+        windowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
         isNotInRecents = in.readBoolean();
-        startLeash = in.readParcelable(null);
-        startBounds = in.readParcelable(null);
-        pictureInPictureParams = in.readParcelable(null);
+        startLeash = in.readTypedObject(SurfaceControl.CREATOR);
+        startBounds = in.readTypedObject(Rect.CREATOR);
+        pictureInPictureParams = in.readTypedObject(PictureInPictureParams.CREATOR);
+        windowType = in.readInt();
     }
 
     @Override
@@ -247,20 +268,21 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(taskId);
         dest.writeInt(mode);
-        dest.writeParcelable(leash, 0 /* flags */);
+        dest.writeTypedObject(leash, 0 /* flags */);
         dest.writeBoolean(isTranslucent);
-        dest.writeParcelable(clipRect, 0 /* flags */);
-        dest.writeParcelable(contentInsets, 0 /* flags */);
+        dest.writeTypedObject(clipRect, 0 /* flags */);
+        dest.writeTypedObject(contentInsets, 0 /* flags */);
         dest.writeInt(prefixOrderIndex);
-        dest.writeParcelable(position, 0 /* flags */);
-        dest.writeParcelable(localBounds, 0 /* flags */);
-        dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
-        dest.writeParcelable(screenSpaceBounds, 0 /* flags */);
-        dest.writeParcelable(windowConfiguration, 0 /* flags */);
+        dest.writeTypedObject(position, 0 /* flags */);
+        dest.writeTypedObject(localBounds, 0 /* flags */);
+        dest.writeTypedObject(sourceContainerBounds, 0 /* flags */);
+        dest.writeTypedObject(screenSpaceBounds, 0 /* flags */);
+        dest.writeTypedObject(windowConfiguration, 0 /* flags */);
         dest.writeBoolean(isNotInRecents);
-        dest.writeParcelable(startLeash, 0 /* flags */);
-        dest.writeParcelable(startBounds, 0 /* flags */);
-        dest.writeParcelable(pictureInPictureParams, 0 /* flags */);
+        dest.writeTypedObject(startLeash, 0 /* flags */);
+        dest.writeTypedObject(startBounds, 0 /* flags */);
+        dest.writeTypedObject(pictureInPictureParams, 0 /* flags */);
+        dest.writeInt(windowType);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -274,6 +296,7 @@
         pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
         pw.print(" screenSpaceBounds="); screenSpaceBounds.printShortString(pw);
         pw.print(" localBounds="); localBounds.printShortString(pw);
+        pw.print(" windowType="); pw.print(windowType);
         pw.println();
         pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
         pw.print(prefix); pw.print("leash="); pw.println(leash);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ec7e4c1..9688c67 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -544,6 +544,7 @@
         // recreate this Surface, so only release it when we are fully
         // detached.
         if (mSurfacePackage != null) {
+            mTmpTransaction.reparent(mSurfacePackage.getSurfaceControl(), null).apply();
             mSurfacePackage.release();
             mSurfacePackage = null;
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ebef464..ab7732b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22188,9 +22188,6 @@
      * and hardware acceleration.
      */
     boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
-        // Clear the overscroll effect:
-        // TODO: Use internal API instead of overriding the existing RenderEffect
-        setRenderEffect(null);
 
         final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
         /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index c2f17c3..ec23a29 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -310,6 +310,18 @@
      */
     private static final float AMBIGUOUS_GESTURE_MULTIPLIER = 2f;
 
+    /**
+     * The timeout value in milliseconds to adjust the selection span and actions for the selected
+     * text when TextClassifier has been initialized.
+     */
+    private static final int SMART_SELECTION_INITIALIZED_TIMEOUT_IN_MILLISECOND = 200;
+
+    /**
+     * The timeout value in milliseconds to adjust the selection span and actions for the selected
+     * text when TextClassifier has not been initialized.
+     */
+    private static final int SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND = 500;
+
     private final boolean mConstructedWithContext;
     private final int mEdgeSlop;
     private final int mFadingEdgeLength;
@@ -335,6 +347,8 @@
     private final float mHorizontalScrollFactor;
     private final boolean mShowMenuShortcutsWhenKeyboardPresent;
     private final long mScreenshotChordKeyTimeout;
+    private final int mSmartSelectionInitializedTimeout;
+    private final int mSmartSelectionInitializingTimeout;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768915)
     private boolean sHasPermanentMenuKey;
@@ -378,6 +392,8 @@
         // Getter throws if mConstructedWithContext is false so doesn't matter what
         // this value is.
         mMinScalingSpan = 0;
+        mSmartSelectionInitializedTimeout = SMART_SELECTION_INITIALIZED_TIMEOUT_IN_MILLISECOND;
+        mSmartSelectionInitializingTimeout = SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND;
     }
 
     /**
@@ -488,6 +504,11 @@
 
         mScreenshotChordKeyTimeout = res.getInteger(
                 com.android.internal.R.integer.config_screenshotChordKeyTimeout);
+
+        mSmartSelectionInitializedTimeout = res.getInteger(
+                com.android.internal.R.integer.config_smartSelectionInitializedTimeoutMillis);
+        mSmartSelectionInitializingTimeout = res.getInteger(
+                com.android.internal.R.integer.config_smartSelectionInitializingTimeoutMillis);
     }
 
     /**
@@ -1069,6 +1090,24 @@
     }
 
     /**
+     * @return the timeout value in milliseconds to adjust the selection span and actions for the
+     *         selected text when TextClassifier has been initialized.
+     * @hide
+     */
+    public int getSmartSelectionInitializedTimeout() {
+        return mSmartSelectionInitializedTimeout;
+    }
+
+    /**
+     * @return the timeout value in milliseconds to adjust the selection span and actions for the
+     *         selected text when TextClassifier has not been initialized.
+     * @hide
+     */
+    public int getSmartSelectionInitializingTimeout() {
+        return mSmartSelectionInitializingTimeout;
+    }
+
+    /**
      * @return the duration in milliseconds before an end of a long press causes a tooltip to be
      * hidden
      * @hide
diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java
index d4aaa61..36bf532 100644
--- a/core/java/android/view/ViewFrameInfo.java
+++ b/core/java/android/view/ViewFrameInfo.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.graphics.FrameInfo;
+import android.os.IInputConstants;
 
 /**
  * The timing information of events taking place in ViewRootImpl
@@ -24,32 +25,14 @@
  */
 public class ViewFrameInfo {
     public long drawStart;
-    public long oldestInputEventTime; // the time of the oldest input event consumed for this frame
-    public long newestInputEventTime; // the time of the newest input event consumed for this frame
+
+
     // Various flags set to provide extra metadata about the current frame. See flag definitions
     // inside FrameInfo.
     // @see android.graphics.FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED
     public long flags;
 
-    /**
-     * Update the oldest event time.
-     * @param eventTime the time of the input event
-     */
-    public void updateOldestInputEvent(long eventTime) {
-        if (oldestInputEventTime == 0 || eventTime < oldestInputEventTime) {
-            oldestInputEventTime = eventTime;
-        }
-    }
-
-    /**
-     * Update the newest event time.
-     * @param eventTime the time of the input event
-     */
-    public void updateNewestInputEvent(long eventTime) {
-        if (newestInputEventTime == 0 || eventTime > newestInputEventTime) {
-            newestInputEventTime = eventTime;
-        }
-    }
+    private int mInputEventId;
 
     /**
      * Populate the missing fields using the data from ViewFrameInfo
@@ -58,8 +41,7 @@
     public void populateFrameInfo(FrameInfo frameInfo) {
         frameInfo.frameInfo[FrameInfo.FLAGS] |= flags;
         frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart;
-        // TODO(b/169866723): Use InputEventAssigner
-        frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID] = newestInputEventTime;
+        frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID] = mInputEventId;
     }
 
     /**
@@ -67,8 +49,7 @@
      */
     public void reset() {
         drawStart = 0;
-        oldestInputEventTime = 0;
-        newestInputEventTime = 0;
+        mInputEventId = IInputConstants.INVALID_INPUT_EVENT_ID;
         flags = 0;
     }
 
@@ -78,4 +59,12 @@
     public void markDrawStart() {
         drawStart = System.nanoTime();
     }
+
+    /**
+     * Assign the value for input event id
+     * @param eventId the id of the input event
+     */
+    public void setInputEvent(int eventId) {
+        mInputEventId = eventId;
+    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f8e65bd..390e3ae 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -457,6 +457,7 @@
     FallbackEventHandler mFallbackEventHandler;
     final Choreographer mChoreographer;
     protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
+    private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
 
     /**
      * Update the Choreographer's FrameInfo object with the timing information for the current
@@ -8352,16 +8353,7 @@
             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                     mPendingInputEventCount);
 
-            long eventTime = q.mEvent.getEventTimeNano();
-            long oldestEventTime = eventTime;
-            if (q.mEvent instanceof MotionEvent) {
-                MotionEvent me = (MotionEvent)q.mEvent;
-                if (me.getHistorySize() > 0) {
-                    oldestEventTime = me.getHistoricalEventTimeNano(0);
-                }
-            }
-            mViewFrameInfo.updateOldestInputEvent(oldestEventTime);
-            mViewFrameInfo.updateNewestInputEvent(eventTime);
+            mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
 
             deliverInputEvent(q);
         }
@@ -8497,6 +8489,11 @@
             consumedBatches = false;
         }
         doProcessInputEvents();
+        if (consumedBatches) {
+            // Must be done after we processed the input events, to mark the completion of the frame
+            // from the input point of view
+            mInputEventAssigner.onChoreographerCallback();
+        }
         return consumedBatches;
     }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 221b334..cf5ec8d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1716,13 +1716,22 @@
      * For the blur region to be visible, the window has to be translucent. See
      * {@link android.R.styleable#Window_windowIsTranslucent}.
      *
-     * Note the difference with {@link android.view.WindowManager.LayoutParams#blurBehindRadius},
+     * Note the difference with {@link WindowManager.LayoutParams#setBlurBehindRadius},
      * which blurs the whole screen behind the window. Background blur blurs the screen behind
      * only within the bounds of the window.
      *
+     * Some devices might not support cross-window blur due to GPU limitations. It can also be
+     * disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, resulting in a transparent window background. To avoid this, the app might want to
+     * change its theme to one that does not use blurs. To listen for cross-window blur
+     * enabled/disabled events, use {@link WindowManager#addCrossWindowBlurEnabledListener}.
+     *
      * @param blurRadius The blur radius to use for window background blur in pixels
      *
      * @see android.R.styleable#Window_windowBackgroundBlurRadius
+     * @see WindowManager.LayoutParams#setBlurBehindRadius
+     * @see WindowManager#addCrossWindowBlurEnabledListener
      */
     public void setBackgroundBlurRadius(int blurRadius) {}
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9e87c95..1819da4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -82,6 +82,7 @@
 
 import android.Manifest.permission;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -120,6 +121,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * The interface that apps use to talk to the window manager.
@@ -808,6 +810,64 @@
         return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
     }
 
+    /**
+     * Returns whether cross-window blur is currently enabled. This affects both window blur behind
+     * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur (see
+     * {@link Window#setBackgroundBlurRadius}).
+     *
+     * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+     * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+     * change its theme to one that does not use blurs. To listen for cross-window blur
+     * enabled/disabled events, use {@link #addCrossWindowBlurEnabledListener}.
+     *
+     * @see #addCrossWindowBlurEnabledListener
+     * @see LayoutParams#setBlurBehindRadius
+     * @see Window#setBackgroundBlurRadius
+     */
+    default boolean isCrossWindowBlurEnabled() {
+        return false;
+    }
+
+    /**
+     * Adds a listener, which will be called when cross-window blurs are enabled/disabled at
+     * runtime. This affects both window blur behind (see {@link LayoutParams#setBlurBehindRadius})
+     * and window background blur (see {@link Window#setBackgroundBlurRadius}).
+     *
+     * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+     * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+     * change its theme to one that does not use blurs.
+     *
+     * The listener will be called on the main thread.
+     *
+     * If the listener is added successfully, it will be called immediately with the current
+     * cross-window blur enabled state.
+     *
+     *
+     * @param listener the listener to be added. It will be called back with a boolean parameter,
+     *                 which is true if cross-window blur is enabled and false if it is disabled
+     *
+     * @see #removeCrossWindowBlurEnabledListener
+     * @see #isCrossWindowBlurEnabled
+     * @see LayoutParams#setBlurBehindRadius
+     * @see Window#setBackgroundBlurRadius
+     */
+    default void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+    }
+
+    /**
+     * Removes a listener, previously added with {@link #addCrossWindowBlurEnabledListener}
+     *
+     * @param listener the listener to be removed
+     *
+     * @see #addCrossWindowBlurEnabledListener
+     */
+    default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+    }
+
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
         /**
          * X position for this window.  With the default gravity it is ignored.
@@ -2722,6 +2782,15 @@
         public boolean hasManualSurfaceInsets;
 
         /**
+         * Whether we should use global insets state when report insets to the window. When set to
+         * {@code true}, all the insets will be reported to the window regardless of the z-order.
+         * Otherwise, only the insets above the given window will be reported.
+         *
+         * @hide
+         */
+        public boolean receiveInsetsIgnoringZOrder;
+
+        /**
          * Whether the previous surface insets should be used vs. what is currently set. When set
          * to {@code true}, the view root will ignore surfaces insets in this object and use what
          * it currently has.
@@ -3238,9 +3307,9 @@
          * The blur behind radius range starts at 0, which means no blur, and increases until 150
          * for the densest blur.
          *
-         * @see #FLAG_BLUR_BEHIND
+         * @see #setBlurBehindRadius
          */
-        public int blurBehindRadius = 0;
+        private int mBlurBehindRadius = 0;
 
         /**
          * The color mode requested by this window. The target display may
@@ -3534,6 +3603,50 @@
             return mColorMode;
         }
 
+        /**
+         * Blurs the screen behind the window. The effect is similar to that of {@link #dimAmount},
+         * but instead of dimmed, the content behind the window will be blurred (or combined with
+         * the dim amount, if such is specified).
+         *
+         * The density of the blur is set by the blur radius. The radius defines the size
+         * of the neighbouring area, from which pixels will be averaged to form the final
+         * color for each pixel. The operation approximates a Gaussian blur.
+         * A radius of 0 means no blur. The higher the radius, the denser the blur.
+         *
+         * Note the difference with {@link android.view.Window#setBackgroundBlurRadius},
+         * which blurs only within the bounds of the window. Blur behind blurs the whole screen
+         * behind the window.
+         *
+         * Requires {@link #FLAG_BLUR_BEHIND} to be set.
+         *
+         * Cross-window blur might not be supported by some devices due to GPU limitations. It can
+         * also be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling
+         * is used or when minimal post processing is requested. In such situations, no blur will
+         * be computed or drawn, resulting in there being no depth separation between the window
+         * and the content behind it. To avoid this, the app might want to use more
+         * {@link #dimAmount} on its window. To listen for cross-window blur enabled/disabled
+         * events, use {@link #addCrossWindowBlurEnabledListener}.
+         *
+         * @param blurBehindRadius The blur radius to use for blur behind in pixels
+         *
+         * @see #FLAG_BLUR_BEHIND
+         * @see #getBlurBehindRadius
+         * @see WindowManager#addCrossWindowBlurEnabledListener
+         * @see Window#setBackgroundBlurRadius
+         */
+        public void setBlurBehindRadius(@IntRange(from = 0) int blurBehindRadius) {
+            mBlurBehindRadius = blurBehindRadius;
+        }
+
+        /**
+         * Returns the blur behind radius of the window.
+         *
+         * @see #setBlurBehindRadius
+         */
+        public int getBlurBehindRadius() {
+            return mBlurBehindRadius;
+        }
+
         /** @hide */
         @SystemApi
         public final void setUserActivityTimeout(long timeout) {
@@ -3610,15 +3723,16 @@
             out.writeInt(preferredDisplayModeId);
             out.writeInt(systemUiVisibility);
             out.writeInt(subtreeSystemUiVisibility);
-            out.writeInt(hasSystemUiListeners ? 1 : 0);
+            out.writeBoolean(hasSystemUiListeners);
             out.writeInt(inputFeatures);
             out.writeLong(userActivityTimeout);
             out.writeInt(surfaceInsets.left);
             out.writeInt(surfaceInsets.top);
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
-            out.writeInt(hasManualSurfaceInsets ? 1 : 0);
-            out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
+            out.writeBoolean(hasManualSurfaceInsets);
+            out.writeBoolean(receiveInsetsIgnoringZOrder);
+            out.writeBoolean(preservePreviousSurfaceInsets);
             out.writeLong(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
             out.writeInt(mColorMode);
@@ -3629,7 +3743,7 @@
             out.writeInt(mFitInsetsSides);
             out.writeBoolean(mFitInsetsIgnoringVisibility);
             out.writeBoolean(preferMinimalPostProcessing);
-            out.writeInt(blurBehindRadius);
+            out.writeInt(mBlurBehindRadius);
             if (providesInsetsTypes != null) {
                 out.writeInt(providesInsetsTypes.length);
                 out.writeIntArray(providesInsetsTypes);
@@ -3679,15 +3793,16 @@
             preferredDisplayModeId = in.readInt();
             systemUiVisibility = in.readInt();
             subtreeSystemUiVisibility = in.readInt();
-            hasSystemUiListeners = in.readInt() != 0;
+            hasSystemUiListeners = in.readBoolean();
             inputFeatures = in.readInt();
             userActivityTimeout = in.readLong();
             surfaceInsets.left = in.readInt();
             surfaceInsets.top = in.readInt();
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
-            hasManualSurfaceInsets = in.readInt() != 0;
-            preservePreviousSurfaceInsets = in.readInt() != 0;
+            hasManualSurfaceInsets = in.readBoolean();
+            receiveInsetsIgnoringZOrder = in.readBoolean();
+            preservePreviousSurfaceInsets = in.readBoolean();
             accessibilityIdOfAnchor = in.readLong();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             mColorMode = in.readInt();
@@ -3698,7 +3813,7 @@
             mFitInsetsSides = in.readInt();
             mFitInsetsIgnoringVisibility = in.readBoolean();
             preferMinimalPostProcessing = in.readBoolean();
-            blurBehindRadius = in.readInt();
+            mBlurBehindRadius = in.readInt();
             int insetsTypesLength = in.readInt();
             if (insetsTypesLength > 0) {
                 providesInsetsTypes = new int[insetsTypesLength];
@@ -3752,7 +3867,7 @@
         /** {@hide} */
         public static final int MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED = 1 << 28;
         /** {@hide} */
-        public static final int BACKGROUND_BLUR_RADIUS_CHANGED = 1 << 29;
+        public static final int BLUR_BEHIND_RADIUS_CHANGED = 1 << 29;
 
         // internal buffer to backup/restore parameters under compatibility mode.
         private int[] mCompatibilityParamsBackup = null;
@@ -3916,6 +4031,11 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (receiveInsetsIgnoringZOrder != o.receiveInsetsIgnoringZOrder) {
+                receiveInsetsIgnoringZOrder = o.receiveInsetsIgnoringZOrder;
+                changes |= SURFACE_INSETS_CHANGED;
+            }
+
             if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) {
                 preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets;
                 changes |= SURFACE_INSETS_CHANGED;
@@ -3943,9 +4063,9 @@
                 changes |= MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED;
             }
 
-            if (blurBehindRadius != o.blurBehindRadius) {
-                blurBehindRadius = o.blurBehindRadius;
-                changes |= BACKGROUND_BLUR_RADIUS_CHANGED;
+            if (mBlurBehindRadius != o.mBlurBehindRadius) {
+                mBlurBehindRadius = o.mBlurBehindRadius;
+                changes |= BLUR_BEHIND_RADIUS_CHANGED;
             }
 
             // This can't change, it's only set at window creation time.
@@ -4104,6 +4224,9 @@
                     sb.append(" (!preservePreviousSurfaceInsets)");
                 }
             }
+            if (receiveInsetsIgnoringZOrder) {
+                sb.append(" receive insets ignoring z-order");
+            }
             if (mColorMode != COLOR_MODE_DEFAULT) {
                 sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode));
             }
@@ -4111,9 +4234,9 @@
                 sb.append(" preferMinimalPostProcessing=");
                 sb.append(preferMinimalPostProcessing);
             }
-            if (blurBehindRadius != 0) {
+            if (mBlurBehindRadius != 0) {
                 sb.append(" blurBehindRadius=");
-                sb.append(blurBehindRadius);
+                sb.append(mBlurBehindRadius);
             }
             sb.append(System.lineSeparator());
             sb.append(prefix).append("  fl=").append(
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 23842b3..b398707 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -40,6 +40,7 @@
 import com.android.internal.os.IResultReceiver;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Provides low-level communication with the system window manager for
@@ -301,4 +302,19 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    @Override
+    public boolean isCrossWindowBlurEnabled() {
+        return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled();
+    }
+
+    @Override
+    public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+        CrossWindowBlurListeners.getInstance().addListener(listener);
+    }
+
+    @Override
+    public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+        CrossWindowBlurListeners.getInstance().removeListener(listener);
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 97ce92c..ab46170 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1781,8 +1781,12 @@
      * @param viewId The fully qualified resource name of the view id to find.
      * @return A list of node info.
      */
-    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(@NonNull String viewId) {
         enforceSealed();
+        if (viewId == null) {
+            Log.e(TAG, "returns empty list due to null viewId.");
+            return Collections.emptyList();
+        }
         if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return Collections.emptyList();
         }
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 9bf3626..9998fbc 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.TaskInfo;
+import android.app.assist.ActivityId;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.LocusId;
@@ -36,6 +37,8 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
 /**
  * Context associated with a {@link ContentCaptureSession} - see {@link ContentCaptureManager} for
  * more info.
@@ -99,16 +102,17 @@
 
     // Fields below are set by server when the session starts
     private final @Nullable ComponentName mComponentName;
-    private final int mTaskId;
     private final int mFlags;
     private final int mDisplayId;
+    private final ActivityId mActivityId;
 
     // Fields below are set by the service upon "delivery" and are not marshalled in the parcel
     private int mParentSessionId = NO_SESSION_ID;
 
     /** @hide */
     public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
-            @NonNull ComponentName componentName, int taskId, int displayId, int flags) {
+            @NonNull ActivityId activityId, @NonNull ComponentName componentName, int displayId,
+            int flags) {
         if (clientContext != null) {
             mHasClientContext = true;
             mExtras = clientContext.mExtras;
@@ -118,10 +122,10 @@
             mExtras = null;
             mId = null;
         }
-        mComponentName = Preconditions.checkNotNull(componentName);
-        mTaskId = taskId;
-        mDisplayId = displayId;
+        mComponentName = Objects.requireNonNull(componentName);
         mFlags = flags;
+        mDisplayId = displayId;
+        mActivityId = activityId;
     }
 
     private ContentCaptureContext(@NonNull Builder builder) {
@@ -130,8 +134,9 @@
         mId = builder.mId;
 
         mComponentName  = null;
-        mTaskId = mFlags = 0;
+        mFlags = 0;
         mDisplayId = Display.INVALID_DISPLAY;
+        mActivityId = null;
     }
 
     /** @hide */
@@ -140,9 +145,9 @@
         mExtras = original.mExtras;
         mId = original.mId;
         mComponentName = original.mComponentName;
-        mTaskId = original.mTaskId;
         mFlags = original.mFlags | extraFlags;
         mDisplayId = original.mDisplayId;
+        mActivityId = original.mActivityId;
     }
 
     /**
@@ -170,7 +175,7 @@
      */
     @SystemApi
     public int getTaskId() {
-        return mTaskId;
+        return mHasClientContext ? 0 : mActivityId.getTaskId();
     }
 
     /**
@@ -184,6 +189,18 @@
     }
 
     /**
+     * Gets the Activity id information associated with this context, or {@code null} when it is a
+     * child session.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public ActivityId getActivityId() {
+        return mHasClientContext ? null : mActivityId;
+    }
+
+    /**
      * Gets the id of the session that originated this session (through
      * {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}),
      * or {@code null} if this is the main session associated with the Activity's {@link Context}.
@@ -309,7 +326,7 @@
         if (mId != null) {
             pw.print(", id="); mId.dump(pw);
         }
-        pw.print(", taskId="); pw.print(mTaskId);
+        pw.print(", activityId="); pw.print(mActivityId);
         pw.print(", displayId="); pw.print(mDisplayId);
         if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentId="); pw.print(mParentSessionId);
@@ -333,7 +350,7 @@
 
         if (fromServer()) {
             builder.append("act=").append(ComponentName.flattenToShortString(mComponentName))
-                .append(", taskId=").append(mTaskId)
+                .append(", activityId=").append(mActivityId)
                 .append(", displayId=").append(mDisplayId)
                 .append(", flags=").append(mFlags);
         } else {
@@ -363,9 +380,9 @@
         }
         parcel.writeParcelable(mComponentName, flags);
         if (fromServer()) {
-            parcel.writeInt(mTaskId);
             parcel.writeInt(mDisplayId);
             parcel.writeInt(mFlags);
+            mActivityId.writeToParcel(parcel, flags);
         }
     }
 
@@ -393,11 +410,12 @@
                 // Client-state only
                 return clientContext;
             } else {
-                final int taskId = parcel.readInt();
                 final int displayId = parcel.readInt();
                 final int flags = parcel.readInt();
-                return new ContentCaptureContext(clientContext, componentName, taskId, displayId,
-                        flags);
+                final ActivityId activityId = new ActivityId(parcel);
+
+                return new ContentCaptureContext(clientContext, activityId, componentName,
+                        displayId, flags);
             }
         }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 10f6c61..9523bcd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -23,10 +23,13 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
+import android.annotation.UserIdInt;
+import android.app.Service;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
@@ -432,10 +435,11 @@
     /** @hide */
     @UiThread
     public void onActivityCreated(@NonNull IBinder applicationToken,
-            @NonNull ComponentName activityComponent) {
+            @NonNull IBinder shareableActivityToken, @NonNull ComponentName activityComponent) {
         if (mOptions.lite) return;
         synchronized (mLock) {
-            getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
+            getMainContentCaptureSession().start(applicationToken, shareableActivityToken,
+                    activityComponent, mFlags);
         }
     }
 
@@ -755,6 +759,74 @@
         }
     }
 
+    /**
+     * Resets the temporary content capture service implementation to the default component.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+    public static void resetTemporaryService(@UserIdInt int userId) {
+        final IContentCaptureManager service = getService();
+        if (service == null) {
+            Log.e(TAG, "IContentCaptureManager is null");
+        }
+        try {
+            service.resetTemporaryService(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Temporarily sets the content capture service implementation.
+     *
+     * @param userId user Id to set the temporary service on.
+     * @param serviceName name of the new component
+     * @param duration how long the change will be valid (the service will be automatically reset
+     * to the default component after this timeout expires).
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+    public static void setTemporaryService(
+            @UserIdInt int userId, @NonNull String serviceName, int duration) {
+        final IContentCaptureManager service = getService();
+        if (service == null) {
+            Log.e(TAG, "IContentCaptureManager is null");
+        }
+        try {
+            service.setTemporaryService(userId, serviceName, duration);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets whether the default content capture service should be used.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+    public static void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+        final IContentCaptureManager service = getService();
+        if (service == null) {
+            Log.e(TAG, "IContentCaptureManager is null");
+        }
+        try {
+            service.setDefaultServiceEnabled(userId, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private static IContentCaptureManager getService() {
+        return IContentCaptureManager.Stub.asInterface(ServiceManager.getService(
+                Service.CONTENT_CAPTURE_MANAGER_SERVICE));
+    }
+
     private interface MyRunnable {
         void run(@NonNull SyncResultReceiver receiver) throws RemoteException;
     }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 01ead46..a641110 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -22,6 +22,7 @@
 import android.view.contentcapture.DataRemovalRequest;
 import android.view.contentcapture.DataShareRequest;
 import android.view.contentcapture.IDataShareWriteAdapter;
+import android.view.contentcapture.IContentCaptureOptionsCallback;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 
@@ -44,8 +45,9 @@
      * @param flags Meta flags that enable or disable content capture (see
      *     {@link IContentCaptureContext#flags}).
      */
-    void startSession(IBinder activityToken, in ComponentName componentName,
-                      int sessionId, int flags, in IResultReceiver result);
+    void startSession(IBinder activityToken, IBinder shareableActivityToken,
+                      in ComponentName componentName, int sessionId, int flags,
+                      in IResultReceiver result);
 
     /**
      * Marks the end of a session for the calling user identified by
@@ -85,4 +87,25 @@
      * Returns a list with the ContentCaptureConditions for the package (or null if not defined).
      */
     void getContentCaptureConditions(String packageName, in IResultReceiver result);
+
+    /**
+     * Resets the temporary service implementation to the default component.
+     */
+    void resetTemporaryService(int userId);
+
+    /**
+     * Temporarily sets the service implementation.
+     */
+    void setTemporaryService(int userId, in String serviceName, int duration);
+
+    /**
+     * Sets whether the default service should be used.
+     */
+    void setDefaultServiceEnabled(int userId, boolean enabled);
+
+    /**
+     * Registers a listener to handle updates ContentCaptureOptions from server.
+     */
+    void registerContentCaptureOptionsCallback(String packageName,
+                                               in IContentCaptureOptionsCallback callback);
 }
diff --git a/core/java/android/view/contentcapture/IContentCaptureOptionsCallback.aidl b/core/java/android/view/contentcapture/IContentCaptureOptionsCallback.aidl
new file mode 100644
index 0000000..b0f062d
--- /dev/null
+++ b/core/java/android/view/contentcapture/IContentCaptureOptionsCallback.aidl
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentcapture;
+
+import android.content.ContentCaptureOptions;
+
+/**
+  * Callback for changes to content capture options made by ContentCaptureService.
+  * Callback interface used by IContentCaptureManager to send asynchronous
+  * notifications back to its clients.  Note that this is a
+  * one-way interface so the server does not block waiting for the client.
+  *
+  * @hide
+  */
+oneway interface IContentCaptureOptionsCallback {
+    void setContentCaptureOptions(in ContentCaptureOptions options);
+}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 3c18b6b..5ca793e 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -123,6 +123,8 @@
 
     @Nullable
     private IBinder mApplicationToken;
+    @Nullable
+    private IBinder mShareableActivityToken;
 
     @Nullable
     private ComponentName mComponentName;
@@ -217,8 +219,8 @@
      * Starts this session.
      */
     @UiThread
-    void start(@NonNull IBinder token, @NonNull ComponentName component,
-            int flags) {
+    void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
+            @NonNull ComponentName component, int flags) {
         if (!isContentCaptureEnabled()) return;
 
         if (sVerbose) {
@@ -237,6 +239,7 @@
         }
         mState = STATE_WAITING_FOR_SERVER;
         mApplicationToken = token;
+        mShareableActivityToken = shareableActivityToken;
         mComponentName = component;
 
         if (sVerbose) {
@@ -245,8 +248,8 @@
         }
 
         try {
-            mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
-                    mSessionStateReceiver);
+            mSystemServerInterface.startSession(mApplicationToken, mShareableActivityToken,
+                    component, mId, flags, mSessionStateReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
         }
@@ -583,6 +586,7 @@
         mDisabled.set((newState & STATE_DISABLED) != 0);
         // TODO(b/122454205): must reset children (which currently is owned by superclass)
         mApplicationToken = null;
+        mShareableActivityToken = null;
         mComponentName = null;
         mEvents = null;
         if (mDirectServiceInterface != null) {
@@ -721,6 +725,10 @@
         if (mApplicationToken != null) {
             pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
         }
+        if (mShareableActivityToken != null) {
+            pw.print(prefix); pw.print("sharable activity token: ");
+            pw.println(mShareableActivityToken);
+        }
         if (mComponentName != null) {
             pw.print(prefix); pw.print("component name: ");
             pw.println(mComponentName.flattenToShortString());
diff --git a/core/java/android/view/displayhash/DisplayHashResultCallback.java b/core/java/android/view/displayhash/DisplayHashResultCallback.java
index 15b29ad..04d29ee 100644
--- a/core/java/android/view/displayhash/DisplayHashResultCallback.java
+++ b/core/java/android/view/displayhash/DisplayHashResultCallback.java
@@ -66,12 +66,19 @@
      */
     int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4;
 
+    /**
+     * The hash algorithm sent to generate the hash was invalid. This means the value is not one
+     * of the supported values in {@link DisplayHashManager#getSupportedHashAlgorithms()}
+     */
+    int DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM = -5;
+
     /** @hide */
     @IntDef(prefix = {"DISPLAY_HASH_ERROR_"}, value = {
             DISPLAY_HASH_ERROR_UNKNOWN,
             DISPLAY_HASH_ERROR_INVALID_BOUNDS,
             DISPLAY_HASH_ERROR_MISSING_WINDOW,
-            DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN
+            DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN,
+            DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface DisplayHashErrorCode {
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 6ade5e6..de4554b 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -105,7 +105,7 @@
      */
     @MainThread
     default void initializeInternal(IBinder token, int displayId,
-            IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
+            IInputMethodPrivilegedOperations privilegedOperations) {
         updateInputMethodDisplay(displayId);
         attachToken(token);
     }
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 25712f8..5d876a6 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -18,23 +18,19 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
-import android.inputmethodservice.InputMethodService;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -64,7 +60,6 @@
  * @attr ref android.R.styleable#InputMethod_isDefault
  * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
  * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
- * @attr ref android.R.styleable#InputMethod_configChanges
  */
 public final class InputMethodInfo implements Parcelable {
     static final String TAG = "InputMethodInfo";
@@ -123,12 +118,6 @@
     private final boolean mInlineSuggestionsEnabled;
 
     /**
-     * The flag for configurations IME assumes the responsibility for handling in
-     * {@link InputMethodService#onConfigurationChanged(Configuration)}}.
-     */
-    private final int mHandledConfigChanges;
-
-    /**
      * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
      * @return a unique ID to be returned by {@link #getId()}. We have used
      *         {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -214,8 +203,6 @@
                     false);
             inlineSuggestionsEnabled = sa.getBoolean(
                     com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
-            mHandledConfigChanges = sa.getInt(
-                    com.android.internal.R.styleable.InputMethod_configChanges, 0);
             sa.recycle();
 
             final int depth = parser.getDepth();
@@ -300,7 +287,6 @@
         mIsVrOnly = source.readBoolean();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
         mSubtypes = new InputMethodSubtypeArray(source);
-        mHandledConfigChanges = source.readInt();
         mForceDefault = false;
     }
 
@@ -312,22 +298,7 @@
         this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
                 settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
                 false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
-                0 /* handledConfigChanges */);
-    }
-
-    /**
-     * Temporary API for creating a built-in input method for test.
-     * @hide
-     */
-    @TestApi
-    public InputMethodInfo(@NonNull String packageName, @NonNull String className,
-            @NonNull CharSequence label, @NonNull String settingsActivity,
-            int handledConfigChanges) {
-        this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
-                settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
-                false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges);
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
     }
 
     /**
@@ -339,7 +310,7 @@
             boolean forceDefault) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
                 true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
-                false /* isVrOnly */, 0 /* handledconfigChanges */);
+                false /* isVrOnly */);
     }
 
     /**
@@ -350,8 +321,7 @@
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
-                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
-                0 /* handledConfigChanges */);
+                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
     }
 
     /**
@@ -361,7 +331,7 @@
     public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
-            boolean isVrOnly, int handledConfigChanges) {
+            boolean isVrOnly) {
         final ServiceInfo si = ri.serviceInfo;
         mService = ri;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -373,7 +343,6 @@
         mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
         mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
         mIsVrOnly = isVrOnly;
-        mHandledConfigChanges = handledConfigChanges;
     }
 
     private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
@@ -520,17 +489,6 @@
         }
     }
 
-    /**
-     * Returns the bit mask of kinds of configuration changes that this IME
-     * can handle itself (without being restarted by the system).
-     *
-     * @attr ref android.R.styleable#InputMethod_configChanges
-     */
-    @ActivityInfo.Config
-    public int getConfigChanges() {
-        return mHandledConfigChanges;
-    }
-
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "mId=" + mId
                 + " mSettingsActivityName=" + mSettingsActivityName
@@ -621,7 +579,6 @@
         dest.writeBoolean(mIsVrOnly);
         mService.writeToParcel(dest, flags);
         mSubtypes.writeToParcel(dest);
-        dest.writeInt(mHandledConfigChanges);
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 2975afc..d0959f9 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -90,6 +90,12 @@
     static final String SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND =
             "system_textclassifier_api_timeout_in_second";
 
+    /**
+     * The max amount of characters before and after the selected text that are passed to the
+     * TextClassifier for the smart selection.
+     */
+    private static final String SMART_SELECTION_TRIM_DELTA = "smart_selection_trim_delta";
+
     private static final String DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE = null;
     private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
     private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -100,6 +106,7 @@
     private static final boolean SMART_SELECT_ANIMATION_ENABLED_DEFAULT = true;
     private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
     private static final long SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND_DEFAULT = 60;
+    private static final int SMART_SELECTION_TRIM_DELTA_DEFAULT = 120;
 
     @Nullable
     public String getTextClassifierServicePackageOverride() {
@@ -155,6 +162,12 @@
                 SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND_DEFAULT);
     }
 
+    public int getSmartSelectionTrimDelta() {
+        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+                SMART_SELECTION_TRIM_DELTA,
+                SMART_SELECTION_TRIM_DELTA_DEFAULT);
+    }
+
     void dump(IndentingPrintWriter pw) {
         pw.println("TextClassificationConstants:");
         pw.increaseIndent();
@@ -170,6 +183,7 @@
                 getTextClassifierServicePackageOverride()).println();
         pw.print(SYSTEM_TEXT_CLASSIFIER_API_TIMEOUT_IN_SECOND,
                 getSystemTextClassifierApiTimeoutInSecond()).println();
+        pw.print(SMART_SELECTION_TRIM_DELTA, getSmartSelectionTrimDelta()).println();
         pw.decreaseIndent();
     }
 }
\ No newline at end of file
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
index e175453..872e15e 100644
--- a/core/java/android/view/translation/ITranslationManager.aidl
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -36,6 +36,10 @@
          int sessionId, in IResultReceiver receiver, int userId);
 
     void updateUiTranslationState(int state, in TranslationSpec sourceSpec,
-         in TranslationSpec destSpec, in List<AutofillId> viewIds, in int taskId,
+         in TranslationSpec destSpec, in List<AutofillId> viewIds, IBinder token, int taskId,
+         int userId);
+    // deprecated
+    void updateUiTranslationStateByTaskId(int state, in TranslationSpec sourceSpec,
+         in TranslationSpec destSpec, in List<AutofillId> viewIds, int taskId,
          int userId);
 }
diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java
index ab1bc47..16418a7 100644
--- a/core/java/android/view/translation/TranslationSpec.java
+++ b/core/java/android/view/translation/TranslationSpec.java
@@ -28,7 +28,7 @@
  * <p>This spec help specify information such as the language/locale for the translation, as well
  * as the data format for the translation (text, audio, etc.)</p>
  */
-@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true)
+@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true)
 public final class TranslationSpec implements Parcelable {
 
     /** Data format for translation is text. */
@@ -99,6 +99,18 @@
 
     @Override
     @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationSpec { " +
+                "language = " + mLanguage + ", " +
+                "dataFormat = " + mDataFormat +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
     public boolean equals(@android.annotation.Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
         // boolean fieldNameEquals(TranslationSpec other) { ... }
@@ -175,10 +187,10 @@
     };
 
     @DataClass.Generated(
-            time = 1609964630624L,
+            time = 1614326090637L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/translation/TranslationSpec.java",
-            inputSignatures = "public static final  int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final  int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index 22c3e57..163f832 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -35,6 +35,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.SyncResultReceiver;
 
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -221,6 +222,12 @@
         return mId;
     }
 
+    /** @hide */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix); pw.print("sourceSpec: "); pw.println(mSourceSpec);
+        pw.print(prefix); pw.print("destSpec: "); pw.println(mDestSpec);
+    }
+
     /**
      * Requests a translation for the provided {@link TranslationRequest} using the Translator's
      * source spec and destination spec.
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index b49d3c0..8100612 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -32,11 +32,15 @@
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
 import android.view.autofill.AutofillId;
 import android.view.translation.UiTranslationManager.UiTranslationState;
 
 import com.android.internal.util.function.pooled.PooledLambda;
 
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -130,6 +134,23 @@
     }
 
     /**
+     * Called to dump the translation information for Activity.
+     */
+    public void dump(String outerPrefix, PrintWriter pw) {
+        pw.print(outerPrefix); pw.println("UiTranslationController:");
+        final String pfx = outerPrefix + "  ";
+        pw.print(pfx); pw.print("activity: "); pw.println(mActivity);
+        final int translatorSize = mTranslators.size();
+        pw.print(outerPrefix); pw.print("number translator: "); pw.println(translatorSize);
+        for (int i = 0; i < translatorSize; i++) {
+            pw.print(outerPrefix); pw.print("#"); pw.println(i);
+            final Translator translator = mTranslators.valueAt(i);
+            translator.dump(outerPrefix, pw);
+            pw.println();
+        }
+    }
+
+    /**
      * The method is used by {@link Translator}, it will be called when the translation is done. The
      * translation result can be get from here.
      */
@@ -194,24 +215,19 @@
     private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {
         synchronized (mLock) {
             // Find Views collect the translation data
-            // TODO(b/178084101): try to optimize, e.g. to this in a single traversal
-            final int viewCounts = views.size();
             final ArrayList<TranslationRequest> requests = new ArrayList<>();
-            for (int i = 0; i < viewCounts; i++) {
-                final AutofillId viewAutofillId = views.get(i);
-                final View view = mActivity.findViewByAutofillIdTraversal(viewAutofillId);
-                if (view == null) {
-                    Log.w(TAG, "Can not find the View for autofill id= " + viewAutofillId);
-                    continue;
-                }
-                mViews.put(viewAutofillId, new WeakReference<>(view));
+            final ArrayList<View> foundViews = new ArrayList<>();
+            findViewsTraversalByAutofillIds(views, foundViews);
+            for (int i = 0; i < foundViews.size(); i++) {
+                final View view = foundViews.get(i);
+                final int currentCount = i;
                 mActivity.runOnUiThread(() -> {
                     final TranslationRequest translationRequest = view.onCreateTranslationRequest();
                     if (translationRequest != null
                             && translationRequest.getTranslationText().length() > 0) {
                         requests.add(translationRequest);
                     }
-                    if (requests.size() == viewCounts) {
+                    if (currentCount == (foundViews.size() - 1)) {
                         Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request.");
                         mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                                 UiTranslationController::sendTranslationRequest,
@@ -222,6 +238,42 @@
         }
     }
 
+    private void findViewsTraversalByAutofillIds(List<AutofillId> sourceViewIds,
+            ArrayList<View> foundViews) {
+        final ArrayList<ViewRootImpl> roots =
+                WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
+        for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+            final View rootView = roots.get(rootNum).getView();
+            if (rootView instanceof ViewGroup) {
+                findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds, foundViews);
+            } else {
+                addViewIfNeeded(sourceViewIds, rootView, foundViews);
+            }
+        }
+    }
+
+    private void findViewsTraversalByAutofillIds(ViewGroup viewGroup,
+            List<AutofillId> sourceViewIds, ArrayList<View> foundViews) {
+        final int childCount = viewGroup.getChildCount();
+        for (int i = 0; i < childCount; ++i) {
+            final View child = viewGroup.getChildAt(i);
+            if (child instanceof ViewGroup) {
+                findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds, foundViews);
+            } else {
+                addViewIfNeeded(sourceViewIds, child, foundViews);
+            }
+        }
+    }
+
+    private void addViewIfNeeded(List<AutofillId> sourceViewIds, View view,
+            ArrayList<View> foundViews) {
+        final AutofillId autofillId = view.getAutofillId();
+        if (sourceViewIds.contains(autofillId)) {
+            mViews.put(autofillId, new WeakReference<>(view));
+            foundViews.add(view);
+        }
+    }
+
     private void runForEachView(Consumer<View> action) {
         synchronized (mLock) {
             final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews);
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index eeb463a..a3a6a2e 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.app.assist.ActivityId;
 import android.content.Context;
 import android.os.RemoteException;
 import android.view.View;
@@ -95,26 +96,61 @@
     /**
      * Request ui translation for a given Views.
      *
+     * NOTE: Please use {@code startTranslation(TranslationSpec, TranslationSpec, List<AutofillId>,
+     * ActivityId)} instead.
+     *
      * @param sourceSpec {@link TranslationSpec} for the data to be translated.
      * @param destSpec {@link TranslationSpec} for the translated data.
      * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
      * @param taskId the Activity Task id which needs ui translation
      */
+    // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
     public void startTranslation(@NonNull TranslationSpec sourceSpec,
             @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
             int taskId) {
-        // TODO(b/177789967): Return result code or find a way to notify the status.
-        // TODO(b/177394471): The is a temparary API, the expected is requestUiTranslation(
-        //  TranslationSpec, TranslationSpec,List<AutofillId>, Binder). We may need more time to
-        //  implement it, use task id as initial version for demo.
         Objects.requireNonNull(sourceSpec);
         Objects.requireNonNull(destSpec);
         Objects.requireNonNull(viewIds);
+        if (viewIds.size() == 0) {
+            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
+        }
+        try {
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_STARTED, sourceSpec,
+                    destSpec, viewIds, taskId, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
+    /**
+     * Request ui translation for a given Views.
+     *
+     * @param sourceSpec {@link TranslationSpec} for the data to be translated.
+     * @param destSpec {@link TranslationSpec} for the translated data.
+     * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
+     * @throws NullPointerException the sourceSpec, destSpec, viewIds, activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void startTranslation(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
+            @NonNull ActivityId activityId) {
+        // TODO(b/177789967): Return result code or find a way to notify the status.
+        Objects.requireNonNull(sourceSpec);
+        Objects.requireNonNull(destSpec);
+        Objects.requireNonNull(viewIds);
+        Objects.requireNonNull(activityId);
+        Objects.requireNonNull(activityId.getToken());
+        if (viewIds.size() == 0) {
+            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
+        }
         try {
             mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec,
-                    destSpec, viewIds, taskId, mContext.getUserId());
+                    destSpec, viewIds, activityId.getToken(), activityId.getTaskId(),
+                    mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -124,14 +160,56 @@
      * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
      * longer to show to show the translated text.
      *
+     * NOTE: Please use {@code finishTranslation(ActivityId)} instead.
+     *
      * @param taskId the Activity Task id which needs ui translation
      */
+    // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
     public void finishTranslation(int taskId) {
         try {
-            // TODO(b/177394471): The is a temparary API, the expected is finishUiTranslation(
-            //  Binder). We may need more time to implement it, use task id as initial version.
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_FINISHED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
+     * longer to show to show the translated text.
+     *
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws NullPointerException the activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void finishTranslation(@NonNull ActivityId activityId) {
+        try {
+            Objects.requireNonNull(activityId);
+            Objects.requireNonNull(activityId.getToken());
             mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to pause the current ui translation's {@link Translator} which will switch back to
+     * the original language.
+     *
+     * NOTE: Please use {@code pauseTranslation(ActivityId)} instead.
+     *
+     * @param taskId the Activity Task id which needs ui translation
+     */
+    // TODO, hide the APIs
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void pauseTranslation(int taskId) {
+        try {
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_PAUSED,
                     null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
                     mContext.getUserId());
         } catch (RemoteException e) {
@@ -143,16 +221,18 @@
      * Request to pause the current ui translation's {@link Translator} which will switch back to
      * the original language.
      *
-     * @param taskId the Activity Task id which needs ui translation
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws NullPointerException the activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
-    public void pauseTranslation(int taskId) {
+    public void pauseTranslation(@NonNull ActivityId activityId) {
         try {
-            // TODO(b/177394471): The is a temparary API, the expected is pauseUiTranslation(Binder)
-            // We may need more time to implement it, use task id as initial version for demo
+            Objects.requireNonNull(activityId);
+            Objects.requireNonNull(activityId.getToken());
             mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
-                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
-                    mContext.getUserId());
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -162,18 +242,40 @@
      * Request to resume the paused ui translation's {@link Translator} which will switch to the
      * translated language if the text had been translated.
      *
+     * NOTE: Please use {@code resumeTranslation(ActivityId)} instead.
+     *
      * @param taskId the Activity Task id which needs ui translation
      */
+    // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
     public void resumeTranslation(int taskId) {
         try {
-            // TODO(b/177394471): The is a temparary API, the expected is resumeUiTranslation(
-            //  Binder). We may need more time to implement it, use task id as initial version.
-            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_RESUMED,
                     null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
                     taskId, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Request to resume the paused ui translation's {@link Translator} which will switch to the
+     * translated language if the text had been translated.
+     *
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws NullPointerException the activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void resumeTranslation(@NonNull ActivityId activityId) {
+        try {
+            Objects.requireNonNull(activityId);
+            Objects.requireNonNull(activityId.getToken());
+            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 1b62266..dc42ad5 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -29,7 +29,6 @@
 import android.graphics.Paint;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
-import android.graphics.RenderEffect;
 import android.graphics.RenderNode;
 import android.os.Build;
 import android.util.AttributeSet;
@@ -83,6 +82,8 @@
     public @interface EdgeEffectType {
     }
 
+    private static final float DEFAULT_MAX_STRETCH_INTENSITY = 1.5f;
+
     @SuppressWarnings("UnusedDeclaration")
     private static final String TAG = "EdgeEffect";
 
@@ -128,6 +129,8 @@
 
     private long mStartTime;
     private float mDuration;
+    private float mStretchIntensity = DEFAULT_MAX_STRETCH_INTENSITY;
+    private float mStretchDistance = -1f;
 
     private final Interpolator mInterpolator;
 
@@ -146,6 +149,8 @@
     private float mPullDistance;
 
     private final Rect mBounds = new Rect();
+    private float mWidth;
+    private float mHeight;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769450)
     private final Paint mPaint = new Paint();
     private float mRadius;
@@ -202,6 +207,19 @@
         mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
 
         mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
+
+        mWidth = width;
+        mHeight = height;
+    }
+
+    /**
+     * Configure the distance in pixels to stretch the content. This is only consumed as part
+     * if {@link #setType(int)} is set to {@link #TYPE_STRETCH}
+     * @param stretchDistance Stretch distance in pixels when the target View is overscrolled
+     * @hide
+     */
+    public void setStretchDistance(float stretchDistance) {
+        mStretchDistance = stretchDistance;
     }
 
     /**
@@ -437,6 +455,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setMaxStretchIntensity(float stretchIntensity) {
+        mStretchIntensity = stretchIntensity;
+    }
+
+    /**
      * Set or clear the blend mode. A blend mode defines how source pixels
      * (generated by a drawing command) are composited with the destination pixels
      * (content of the render target).
@@ -520,23 +545,55 @@
             RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
             if (mTmpMatrix == null) {
                 mTmpMatrix = new Matrix();
-                mTmpPoints = new float[4];
+                mTmpPoints = new float[12];
             }
             //noinspection deprecation
             recordingCanvas.getMatrix(mTmpMatrix);
-            mTmpPoints[0] = mBounds.width() * mDisplacement;
-            mTmpPoints[1] = mDistance * mBounds.height();
-            mTmpPoints[2] = mTmpPoints[0];
-            mTmpPoints[3] = 0;
+
+            mTmpPoints[0] = 0;
+            mTmpPoints[1] = 0; // top-left
+            mTmpPoints[2] = mWidth;
+            mTmpPoints[3] = 0; // top-right
+            mTmpPoints[4] = mWidth;
+            mTmpPoints[5] = mHeight; // bottom-right
+            mTmpPoints[6] = 0;
+            mTmpPoints[7] = mHeight; // bottom-left
+            mTmpPoints[8] = mWidth * mDisplacement;
+            mTmpPoints[9] = 0; // drag start point
+            mTmpPoints[10] = mWidth * mDisplacement;
+            mTmpPoints[11] = mHeight * mDistance; // drag point
             mTmpMatrix.mapPoints(mTmpPoints);
-            float x = mTmpPoints[0] - mTmpPoints[2];
-            float y = mTmpPoints[1] - mTmpPoints[3];
 
             RenderNode renderNode = recordingCanvas.mNode;
 
-            // TODO: use stretchy RenderEffect and use internal API when it is ready
-            // TODO: wrap existing RenderEffect
-            renderNode.setRenderEffect(RenderEffect.createOffsetEffect(x, y));
+            float left = renderNode.getLeft()
+                    + min(mTmpPoints[0], mTmpPoints[2], mTmpPoints[4], mTmpPoints[6]);
+            float top = renderNode.getTop()
+                    + min(mTmpPoints[1], mTmpPoints[3], mTmpPoints[5], mTmpPoints[7]);
+            float right = renderNode.getLeft()
+                    + max(mTmpPoints[0], mTmpPoints[2], mTmpPoints[4], mTmpPoints[6]);
+            float bottom = renderNode.getTop()
+                    + max(mTmpPoints[1], mTmpPoints[3], mTmpPoints[5], mTmpPoints[7]);
+            // assume rotations of increments of 90 degrees
+            float x = mTmpPoints[10] - mTmpPoints[8];
+            float width = right - left;
+            float vecX = Math.max(-1f, Math.min(1f, x / width));
+            float y = mTmpPoints[11] - mTmpPoints[9];
+            float height = bottom - top;
+            float vecY = Math.max(-1f, Math.min(1f, y / height));
+            renderNode.stretch(
+                    left,
+                    top,
+                    right,
+                    bottom,
+                    vecX * mStretchIntensity,
+                    vecY * mStretchIntensity,
+                    // TODO (njawad/mount) figure out proper stretch distance from UX
+                    //  for now leverage placeholder logic if no stretch distance is provided to
+                    //  consume the displacement ratio times the minimum of the width or height
+                    mStretchDistance > 0 ? mStretchDistance :
+                            (mDisplacement * Math.min(mWidth, mHeight))
+            );
         }
 
         boolean oneLastFrame = false;
@@ -548,6 +605,18 @@
         return mState != STATE_IDLE || oneLastFrame;
     }
 
+    private float min(float f1, float f2, float f3, float f4) {
+        float min = Math.min(f1, f2);
+        min = Math.min(min, f3);
+        return Math.min(min, f4);
+    }
+
+    private float max(float f1, float f2, float f3, float f4) {
+        float max = Math.max(f1, f2);
+        max = Math.max(max, f3);
+        return Math.max(max, f4);
+    }
+
     /**
      * Return the maximum height that the edge effect will be drawn at given the original
      * {@link #setSize(int, int) input size}.
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 23915e0..bf552e2 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -249,6 +249,26 @@
     }
 
     /**
+     * API used for prototyping stretch effect parameters in framework sample apps
+     * @hide
+     */
+    public void setEdgeEffectIntensity(float intensity) {
+        mEdgeGlowLeft.setMaxStretchIntensity(intensity);
+        mEdgeGlowRight.setMaxStretchIntensity(intensity);
+        invalidate();
+    }
+
+    /**
+     * API used for prototyping stretch effect parameters in the framework sample apps
+     * @hide
+     */
+    public void setStretchDistance(float distance) {
+        mEdgeGlowLeft.setStretchDistance(distance);
+        mEdgeGlowRight.setStretchDistance(distance);
+        invalidate();
+    }
+
+    /**
      * Sets the right edge effect color.
      *
      * @param color The color for the right edge effect.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index e0b4ec7..2cf50bb 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -705,6 +705,14 @@
         public String getPackageName() {
             return mContextForResources.getPackageName();
         }
+
+        @Override
+        public boolean isRestricted() {
+            // Override isRestricted and direct to resource's implementation. The isRestricted is
+            // used for determining the risky resources loading, e.g. fonts, thus direct to context
+            // for resource.
+            return mContextForResources.isRestricted();
+        }
     }
 
     private class SetEmptyView extends Action {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 65f3da7..3006729 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -281,6 +281,26 @@
     }
 
     /**
+     * API used for prototyping stretch effect parameters in framework sample apps
+     * @hide
+     */
+    public void setEdgeEffectIntensity(float intensity) {
+        mEdgeGlowTop.setMaxStretchIntensity(intensity);
+        mEdgeGlowBottom.setMaxStretchIntensity(intensity);
+        invalidate();
+    }
+
+    /**
+     * API used for prototyping stretch effect parameters in the framework sample apps
+     * @hide
+     */
+    public void setStretchDistance(float distance) {
+        mEdgeGlowTop.setStretchDistance(distance);
+        mEdgeGlowBottom.setStretchDistance(distance);
+        invalidate();
+    }
+
+    /**
      * Sets the bottom edge effect color.
      *
      * @param color The color for the bottom edge effect.
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 6f18920..eb6bce4 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -36,6 +36,7 @@
 import android.text.util.Linkify;
 import android.util.Log;
 import android.view.ActionMode;
+import android.view.ViewConfiguration;
 import android.view.textclassifier.ExtrasUtils;
 import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.SelectionEvent.InvocationMethod;
@@ -1056,10 +1057,12 @@
      */
     private static final class TextClassificationHelper {
 
-        private static final int TRIM_DELTA = 120;  // characters
+        // The fixed upper bound of context size.
+        private static final int TRIM_DELTA_UPPER_BOUND = 240;
 
         private final Context mContext;
         private Supplier<TextClassifier> mTextClassifier;
+        private final ViewConfiguration mViewConfiguration;
 
         /** The original TextView text. **/
         private String mText;
@@ -1088,12 +1091,13 @@
         private SelectionResult mLastClassificationResult;
 
         /** Whether the TextClassifier has been initialized. */
-        private boolean mHot;
+        private boolean mInitialized;
 
         TextClassificationHelper(Context context, Supplier<TextClassifier> textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
             init(textClassifier, text, selectionStart, selectionEnd, locales);
             mContext = Objects.requireNonNull(context);
+            mViewConfiguration = ViewConfiguration.get(mContext);
         }
 
         @UiThread
@@ -1110,13 +1114,13 @@
 
         @WorkerThread
         public SelectionResult classifyText() {
-            mHot = true;
+            mInitialized = true;
             return performClassification(null /* selection */);
         }
 
         @WorkerThread
         public SelectionResult suggestSelection() {
-            mHot = true;
+            mInitialized = true;
             trimText();
             final TextSelection selection;
             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
@@ -1148,16 +1152,15 @@
         /**
          * Maximum time (in milliseconds) to wait for a textclassifier result before timing out.
          */
-        // TODO: Consider making this a ViewConfiguration.
         public int getTimeoutDuration() {
-            if (mHot) {
-                return 200;
+            if (mInitialized) {
+                return mViewConfiguration.getSmartSelectionInitializedTimeout();
             } else {
                 // Return a slightly larger number than usual when the TextClassifier is first
                 // initialized. Initialization would usually take longer than subsequent calls to
                 // the TextClassifier. The impact of this on the UI is that we do not show the
                 // selection handles or toolbar until after this timeout.
-                return 500;
+                return mViewConfiguration.getSmartSelectionInitializingTimeout();
             }
         }
 
@@ -1205,8 +1208,11 @@
         }
 
         private void trimText() {
-            mTrimStart = Math.max(0, mSelectionStart - TRIM_DELTA);
-            final int referenceEnd = Math.min(mText.length(), mSelectionEnd + TRIM_DELTA);
+            final int trimDelta = Math.min(
+                    TextClassificationManager.getSettings(mContext).getSmartSelectionTrimDelta(),
+                    TRIM_DELTA_UPPER_BOUND);
+            mTrimStart = Math.max(0, mSelectionStart - trimDelta);
+            final int referenceEnd = Math.min(mText.length(), mSelectionEnd + trimDelta);
             mTrimmedText = mText.subSequence(mTrimStart, referenceEnd);
             mRelativeStart = mSelectionStart - mTrimStart;
             mRelativeEnd = mSelectionEnd - mTrimStart;
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index 63b9e9b..d1c1e40 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -35,6 +35,31 @@
 @TestApi
 public final class StartingWindowInfo implements Parcelable {
     /**
+     * Prefer nothing or not care the type of starting window.
+     * @hide
+     */
+    public static final int STARTING_WINDOW_TYPE_NONE = 0;
+    /**
+     * Prefer splash screen starting window.
+     * @hide
+     */
+    public static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 1;
+    /**
+     * Prefer snapshot starting window.
+     * @hide
+     */
+    public static final int STARTING_WINDOW_TYPE_SNAPSHOT = 2;
+    /**
+     * @hide
+     */
+    @IntDef(flag = true, prefix = "STARTING_WINDOW_TYPE_", value = {
+            STARTING_WINDOW_TYPE_NONE,
+            STARTING_WINDOW_TYPE_SPLASH_SCREEN,
+            STARTING_WINDOW_TYPE_SNAPSHOT
+    })
+    public @interface StartingWindowType {}
+
+    /**
      * The {@link TaskInfo} from this task.
      *  @hide
      */
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index dc07e44..f1e5fb9 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -46,7 +46,7 @@
     private final int mOrientation;
     /** See {@link android.view.Surface.Rotation} */
     @Surface.Rotation
-    private int mRotation;
+    private final int mRotation;
     /** The size of the snapshot before scaling */
     private final Point mTaskSize;
     private final Rect mContentInsets;
@@ -90,15 +90,15 @@
     private TaskSnapshot(Parcel source) {
         mId = source.readLong();
         mTopActivityComponent = ComponentName.readFromParcel(source);
-        mSnapshot = source.readParcelable(null /* classLoader */);
+        mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR);
         int colorSpaceId = source.readInt();
         mColorSpace = colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length
                 ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId])
                 : ColorSpace.get(ColorSpace.Named.SRGB);
         mOrientation = source.readInt();
         mRotation = source.readInt();
-        mTaskSize = source.readParcelable(null /* classLoader */);
-        mContentInsets = source.readParcelable(null /* classLoader */);
+        mTaskSize = source.readTypedObject(Point.CREATOR);
+        mContentInsets = source.readTypedObject(Rect.CREATOR);
         mIsLowResolution = source.readBoolean();
         mIsRealSnapshot = source.readBoolean();
         mWindowingMode = source.readInt();
@@ -235,13 +235,12 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(mId);
         ComponentName.writeToParcel(mTopActivityComponent, dest);
-        dest.writeParcelable(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null,
-                0);
+        dest.writeTypedObject(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null, 0);
         dest.writeInt(mColorSpace.getId());
         dest.writeInt(mOrientation);
         dest.writeInt(mRotation);
-        dest.writeParcelable(mTaskSize, 0);
-        dest.writeParcelable(mContentInsets, 0);
+        dest.writeTypedObject(mTaskSize, 0);
+        dest.writeTypedObject(mContentInsets, 0);
         dest.writeBoolean(mIsLowResolution);
         dest.writeBoolean(mIsRealSnapshot);
         dest.writeInt(mWindowingMode);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3a9f3b9..eecd0cf 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -74,11 +74,11 @@
     @UnsupportedAppUsage
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
     void getHistoricalOps(int uid, String packageName, String attributionTag, in List<String> ops,
-            int filter, long beginTimeMillis, long endTimeMillis, int flags,
+            int historyFlags, int filter, long beginTimeMillis, long endTimeMillis, int flags,
             in RemoteCallback callback);
     void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
-            in List<String> ops, int filter, long beginTimeMillis, long endTimeMillis, int flags,
-            in RemoteCallback callback);
+            in List<String> ops, int historyFlags, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, in RemoteCallback callback);
     void offsetHistory(long duration);
     void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
     void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
diff --git a/core/java/com/android/internal/infra/GlobalWhitelistState.java b/core/java/com/android/internal/infra/GlobalWhitelistState.java
index 3c081e2..7529536 100644
--- a/core/java/com/android/internal/infra/GlobalWhitelistState.java
+++ b/core/java/com/android/internal/infra/GlobalWhitelistState.java
@@ -99,6 +99,18 @@
     }
 
     /**
+     * Gets packages that are either entirely allowlisted or have components that are allowlisted
+     * for the given user.
+     */
+    public ArraySet<String> getWhitelistedPackages(@UserIdInt int userId) {
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) return null;
+            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+            return helper == null ? null : helper.getWhitelistedPackages();
+        }
+    }
+
+    /**
      * Resets the allowlist for the given user.
      */
     public void resetWhitelist(@NonNull int userId) {
diff --git a/core/java/com/android/internal/infra/WhitelistHelper.java b/core/java/com/android/internal/infra/WhitelistHelper.java
index 1d76090..3e93106 100644
--- a/core/java/com/android/internal/infra/WhitelistHelper.java
+++ b/core/java/com/android/internal/infra/WhitelistHelper.java
@@ -140,6 +140,15 @@
         return mWhitelistedPackages == null ? null : mWhitelistedPackages.get(packageName);
     }
 
+    /**
+     * Returns a set of all packages that are either entirely allowlisted or have components that
+     * are allowlisted.
+     */
+    @Nullable
+    public ArraySet<String> getWhitelistedPackages() {
+        return mWhitelistedPackages == null ? null : new ArraySet<>(mWhitelistedPackages.keySet());
+    }
+
     @Override
     public String toString() {
         return "WhitelistHelper[" + mWhitelistedPackages + ']';
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index 2113173..3958b9e 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -225,4 +225,31 @@
             callback.onResult();
         } catch (RemoteException ignored) { }
     }
+
+    /**
+     * A utility method using given {@link IIInputContentUriTokenResultCallback} to callback the
+     * result.
+     *
+     * @param callback {@link IIInputContentUriTokenResultCallback} to be called back.
+     * @param resultSupplier the supplier from which the result is provided.
+     */
+    public static void onResult(@NonNull IIInputContentUriTokenResultCallback callback,
+            @NonNull Supplier<IInputContentUriToken> resultSupplier) {
+        IInputContentUriToken result = null;
+        Throwable exception = null;
+
+        try {
+            result = resultSupplier.get();
+        } catch (Throwable throwable) {
+            exception = throwable;
+        }
+
+        try {
+            if (exception != null) {
+                callback.onError(ThrowableHolder.of(exception));
+                return;
+            }
+            callback.onResult(result);
+        } catch (RemoteException ignored) { }
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index d6a4663..ba3a343 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -444,6 +444,13 @@
     }
 
     /**
+     * @return an instance of {@link Completable.IInputContentUriToken}.
+     */
+    public static Completable.IInputContentUriToken createIInputContentUriToken() {
+        return new Completable.IInputContentUriToken();
+    }
+
+    /**
      * @return an instance of {@link Completable.Void}.
      */
     public static Completable.Void createVoid() {
@@ -497,6 +504,12 @@
             extends Values<List<android.view.inputmethod.InputMethodInfo>> { }
 
     /**
+     * Completable object of {@link IInputContentUriToken>}.
+     */
+    public static final class IInputContentUriToken
+            extends Values<com.android.internal.inputmethod.IInputContentUriToken> { }
+
+    /**
      * Await the result by the {@link Completable.Values}.
      *
      * @return the result once {@link ValueBase#onComplete()}.
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
similarity index 65%
copy from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
copy to core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
index ddb5ef8..2e6d224 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
-package android.content.pm.verify.domain;
+package com.android.internal.inputmethod;
 
-parcelable DomainVerificationUserSelection;
+import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IIInputContentUriTokenResultCallback {
+    void onResult(in IInputContentUriToken result);
+    void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index f0e26cf..e4dd7b0 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -19,25 +19,31 @@
 import android.net.Uri;
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.internal.inputmethod.IBooleanResultCallback;
 import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.IIInputContentUriTokenResultCallback;
+import com.android.internal.inputmethod.IVoidResultCallback;
 
 /**
  * Defines priviledged operations that only the current IME is allowed to call.
  * Actual operations are implemented and handled by InputMethodManagerService.
  */
-interface IInputMethodPrivilegedOperations {
-    void setImeWindowStatus(int vis, int backDisposition);
-    void reportStartInput(in IBinder startInputToken);
-    IInputContentUriToken createInputContentUriToken(in Uri contentUri, in String packageName);
-    void reportFullscreenMode(boolean fullscreen);
-    void setInputMethod(String id);
-    void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype);
-    void hideMySoftInput(int flags);
-    void showMySoftInput(int flags);
-    void updateStatusIcon(String packageName, int iconId);
-    boolean switchToPreviousInputMethod();
-    boolean switchToNextInputMethod(boolean onlyCurrentIme);
-    boolean shouldOfferSwitchingToNextInputMethod();
-    void notifyUserAction();
-    void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible);
+oneway interface IInputMethodPrivilegedOperations {
+    void setImeWindowStatus(int vis, int backDisposition, in IVoidResultCallback resultCallback);
+    void reportStartInput(in IBinder startInputToken, in IVoidResultCallback resultCallback);
+    void createInputContentUriToken(in Uri contentUri, in String packageName,
+            in IIInputContentUriTokenResultCallback resultCallback);
+    void reportFullscreenMode(boolean fullscreen, in IVoidResultCallback resultCallback);
+    void setInputMethod(String id, in IVoidResultCallback resultCallback);
+    void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
+            in IVoidResultCallback resultCallback);
+    void hideMySoftInput(int flags, in IVoidResultCallback resultCallback);
+    void showMySoftInput(int flags, in IVoidResultCallback resultCallback);
+    void updateStatusIcon(String packageName, int iconId, in IVoidResultCallback resultCallback);
+    void switchToPreviousInputMethod(in IBooleanResultCallback resultCallback);
+    void switchToNextInputMethod(boolean onlyCurrentIme, in IBooleanResultCallback resultCallback);
+    void shouldOfferSwitchingToNextInputMethod(in IBooleanResultCallback resultCallback);
+    void notifyUserAction(in IVoidResultCallback resultCallback);
+    void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible,
+            in IVoidResultCallback resultCallback);
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index c353de8..93374ba 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -228,6 +228,8 @@
                 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR";
             case SoftInputShowHideReason.HIDE_REMOVE_CLIENT:
                 return "HIDE_REMOVE_CLIENT";
+            case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY:
+                return "SHOW_RESTORE_IME_VISIBILITY";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index d6730e8..04cf3f3 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -95,7 +95,8 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#setImeWindowStatus(int, int)}.
+     * Calls {@link IInputMethodPrivilegedOperations#setImeWindowStatus(int, int,
+     * IVoidResultCallback)}.
      *
      * @param vis visibility flags
      * @param backDisposition disposition flags
@@ -112,14 +113,17 @@
             return;
         }
         try {
-            ops.setImeWindowStatus(vis, backDisposition);
+            final Completable.Void value = Completable.createVoid();
+            ops.setImeWindowStatus(vis, backDisposition, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#reportStartInput(IBinder)}.
+     * Calls {@link IInputMethodPrivilegedOperations#reportStartInput(IBinder,
+     * IVoidResultCallback)}.
      *
      * @param startInputToken {@link IBinder} token to distinguish startInput session
      */
@@ -130,14 +134,17 @@
             return;
         }
         try {
-            ops.reportStartInput(startInputToken);
+            final Completable.Void value = Completable.createVoid();
+            ops.reportStartInput(startInputToken, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String)}.
+     * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
+     * IIInputContentUriTokenResultCallback)}.
      *
      * @param contentUri Content URI to which a temporary read permission should be granted
      * @param packageName Indicates what package needs to have a temporary read permission
@@ -151,7 +158,10 @@
             return null;
         }
         try {
-            return ops.createInputContentUriToken(contentUri, packageName);
+            final Completable.IInputContentUriToken value =
+                    Completable.createIInputContentUriToken();
+            ops.createInputContentUriToken(contentUri, packageName, ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             // For historical reasons, this error was silently ignored.
             // Note that the caller already logs error so we do not need additional Log.e() here.
@@ -161,7 +171,8 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#reportFullscreenMode(boolean)}.
+     * Calls {@link IInputMethodPrivilegedOperations#reportFullscreenMode(boolean,
+     * IVoidResultCallback)}.
      *
      * @param fullscreen {@code true} if the IME enters full screen mode
      */
@@ -172,14 +183,17 @@
             return;
         }
         try {
-            ops.reportFullscreenMode(fullscreen);
+            final Completable.Void value = Completable.createVoid();
+            ops.reportFullscreenMode(fullscreen, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int)}.
+     * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int,
+     * IVoidResultCallback)}.
      *
      * @param packageName package name from which the status icon should be loaded
      * @param iconResId resource ID of the icon to be loaded
@@ -191,14 +205,16 @@
             return;
         }
         try {
-            ops.updateStatusIcon(packageName, iconResId);
+            final Completable.Void value = Completable.createVoid();
+            ops.updateStatusIcon(packageName, iconResId, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String)}.
+     * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, IVoidResultCallback)}.
      *
      * @param id IME ID of the IME to switch to
      * @see android.view.inputmethod.InputMethodInfo#getId()
@@ -210,7 +226,9 @@
             return;
         }
         try {
-            ops.setInputMethod(id);
+            final Completable.Void value = Completable.createVoid();
+            ops.setInputMethod(id, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -218,7 +236,7 @@
 
     /**
      * Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
-     * InputMethodSubtype)}
+     * InputMethodSubtype, IVoidResultCallback)}
      *
      * @param id IME ID of the IME to switch to
      * @param subtype {@link InputMethodSubtype} to switch to
@@ -231,14 +249,16 @@
             return;
         }
         try {
-            ops.setInputMethodAndSubtype(id, subtype);
+            final Completable.Void value = Completable.createVoid();
+            ops.setInputMethodAndSubtype(id, subtype, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int)}
+     * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, IVoidResultCallback)}
      *
      * @param flags additional operating flags
      * @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
@@ -251,14 +271,16 @@
             return;
         }
         try {
-            ops.hideMySoftInput(flags);
+            final Completable.Void value = Completable.createVoid();
+            ops.hideMySoftInput(flags, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int)}
+     * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, IVoidResultCallback)}
      *
      * @param flags additional operating flags
      * @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
@@ -271,14 +293,17 @@
             return;
         }
         try {
-            ops.showMySoftInput(flags);
+            final Completable.Void value = Completable.createVoid();
+            ops.showMySoftInput(flags, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod()}
+     * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(
+     * IBooleanResultCallback)}
      *
      * @return {@code true} if handled
      */
@@ -289,14 +314,17 @@
             return false;
         }
         try {
-            return ops.switchToPreviousInputMethod();
+            final Completable.Boolean value = Completable.createBoolean();
+            ops.switchToPreviousInputMethod(ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#switchToNextInputMethod(boolean)}
+     * Calls {@link IInputMethodPrivilegedOperations#switchToNextInputMethod(boolean,
+     * IBooleanResultCallback)}
      *
      * @param onlyCurrentIme {@code true} to switch to a {@link InputMethodSubtype} within the same
      *                       IME
@@ -309,14 +337,17 @@
             return false;
         }
         try {
-            return ops.switchToNextInputMethod(onlyCurrentIme);
+            final Completable.Boolean value = Completable.createBoolean();
+            ops.switchToNextInputMethod(onlyCurrentIme, ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod()}
+     * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod(
+     * IBooleanResultCallback)}
      *
      * @return {@code true} if the IEM should offer a way to globally switch IME
      */
@@ -327,14 +358,16 @@
             return false;
         }
         try {
-            return ops.shouldOfferSwitchingToNextInputMethod();
+            final Completable.Boolean value = Completable.createBoolean();
+            ops.shouldOfferSwitchingToNextInputMethod(ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#notifyUserAction()}
+     * Calls {@link IInputMethodPrivilegedOperations#notifyUserAction(IVoidResultCallback)}
      */
     @AnyThread
     public void notifyUserAction() {
@@ -343,14 +376,17 @@
             return;
         }
         try {
-            ops.notifyUserAction();
+            final Completable.Void value = Completable.createVoid();
+            ops.notifyUserAction(ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean)}.
+     * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean,
+     * IVoidResultCallback)}.
      *
      * @param showOrHideInputToken placeholder token that maps to window requesting
      *        {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or
@@ -365,7 +401,9 @@
             return;
         }
         try {
-            ops.applyImeVisibility(showOrHideInputToken, setVisible);
+            final Completable.Void value = Completable.createVoid();
+            ops.applyImeVisibility(showOrHideInputToken, setVisible, ResultCallbacks.of(value));
+            Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 2a48c1f..c56ed2d 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -387,4 +387,41 @@
             }
         };
     }
+
+    /**
+     * Creates {@link IIInputContentUriTokenResultCallback.Stub} that is to set
+     * {@link Completable.IInputContentUriToken} when receiving the result.
+     *
+     * @param value {@link Completable.IInputContentUriToken} to be set when receiving the result.
+     * @return {@link IIInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
+     * parameter.
+     */
+    @AnyThread
+    public static IIInputContentUriTokenResultCallback.Stub of(
+            @NonNull Completable.IInputContentUriToken value) {
+        final AtomicReference<WeakReference<Completable.IInputContentUriToken>>
+                atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+        return new IIInputContentUriTokenResultCallback.Stub() {
+            @BinderThread
+            @Override
+            public void onResult(IInputContentUriToken result) {
+                final Completable.IInputContentUriToken value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onComplete(result);
+            }
+
+            @BinderThread
+            @Override
+            public void onError(ThrowableHolder throwableHolder) {
+                final Completable.IInputContentUriToken value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onError(throwableHolder);
+            }
+        };
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 1553e2e..f1cdf2b 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -49,7 +49,8 @@
         SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
         SoftInputShowHideReason.HIDE_BUBBLES,
         SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR,
-        SoftInputShowHideReason.HIDE_REMOVE_CLIENT})
+        SoftInputShowHideReason.HIDE_REMOVE_CLIENT,
+        SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -167,4 +168,10 @@
      * Hide soft input when a {@link com.android.internal.view.IInputMethodClient} is removed.
      */
     int HIDE_REMOVE_CLIENT = 21;
+
+    /**
+     * Show soft input when the system invoking
+     * {@link com.android.server.wm.WindowManagerInternal#shouldRestoreImeVisibility}.
+     */
+    int SHOW_RESTORE_IME_VISIBILITY = 22;
 }
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 342456a..db0b48e 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -203,6 +203,9 @@
         Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
         mCancelled = true;
         removeObservers();
+        if (mListener != null) {
+            mListener.onNotifyCujEvents(mSession, InteractionJankMonitor.ACTION_SESSION_CANCEL);
+        }
     }
 
     @Override
@@ -324,11 +327,8 @@
             }
             if (info.surfaceControlCallbackFired) {
                 totalFramesCount++;
-
-                // Only count missed frames if it's not stuffed.
                 if ((info.jankType & PREDICTION_ERROR) != 0
-                        || ((info.jankType & JANK_APP_DEADLINE_MISSED) != 0
-                                && (info.jankType & BUFFER_STUFFING) == 0)) {
+                        || ((info.jankType & JANK_APP_DEADLINE_MISSED) != 0)) {
                     Log.w(TAG, "Missed App frame:" + info.jankType);
                     missedAppFramesCount++;
                 }
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 0294ec3..fbc92c1 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -99,7 +99,7 @@
     private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
 
     public static final String ACTION_SESSION_BEGIN = ACTION_PREFIX + ".ACTION_SESSION_BEGIN";
-    public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END";
+    public static final String ACTION_SESSION_CANCEL = ACTION_PREFIX + ".ACTION_SESSION_CANCEL";
     public static final String ACTION_METRICS_LOGGED = ACTION_PREFIX + ".ACTION_METRICS_LOGGED";
     public static final String BUNDLE_KEY_CUJ_NAME = ACTION_PREFIX + ".CUJ_NAME";
     public static final String BUNDLE_KEY_TIMESTAMP = ACTION_PREFIX + ".TIMESTAMP";
diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java
index 571d7e7..052959a 100644
--- a/core/java/com/android/internal/net/NetworkUtilsInternal.java
+++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java
@@ -22,6 +22,8 @@
 import android.annotation.NonNull;
 import android.system.Os;
 
+import java.io.FileDescriptor;
+
 /** @hide */
 public class NetworkUtilsInternal {
 
@@ -36,6 +38,20 @@
     public static native void setAllowNetworkingForProcess(boolean allowNetworking);
 
     /**
+     * Protect {@code fd} from VPN connections.  After protecting, data sent through
+     * this socket will go directly to the underlying network, so its traffic will not be
+     * forwarded through the VPN.
+     */
+    public static native boolean protectFromVpn(FileDescriptor fd);
+
+    /**
+     * Protect {@code socketfd} from VPN connections.  After protecting, data sent through
+     * this socket will go directly to the underlying network, so its traffic will not be
+     * forwarded through the VPN.
+     */
+    public static native boolean protectFromVpn(int socketfd);
+
+    /**
      * Returns true if the hostname is weakly validated.
      * @param hostname Name of host to validate.
      * @return True if it's a valid-ish hostname.
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 9840013..9a91d20 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -124,6 +124,7 @@
 import com.android.internal.widget.FloatingToolbar;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 /** @hide */
 public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
@@ -282,14 +283,19 @@
     private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
     private Insets mBackgroundInsets = Insets.NONE;
     private Insets mLastBackgroundInsets = Insets.NONE;
-    private int mLastBackgroundBlurRadius = 0;
     private boolean mDrawLegacyNavigationBarBackground;
 
     private PendingInsetsController mPendingInsetsController = new PendingInsetsController();
+
+    private int mOriginalBackgroundBlurRadius = 0;
+    private int mBackgroundBlurRadius = 0;
+    private int mLastBackgroundBlurRadius = 0;
+    private boolean mCrossWindowBlurEnabled;
     private final ViewTreeObserver.OnPreDrawListener mBackgroundBlurOnPreDrawListener = () -> {
-        updateBackgroundBlur();
+        updateBackgroundBlurCorners();
         return true;
     };
+    private Consumer<Boolean> mCrossWindowBlurEnabledListener;
 
     DecorView(Context context, int featureId, PhoneWindow window,
             WindowManager.LayoutParams params) {
@@ -1272,23 +1278,17 @@
         }
 
         if (mBackgroundInsets.equals(mLastBackgroundInsets)
-                && mWindow.mBackgroundBlurRadius == mLastBackgroundBlurRadius
+                && mBackgroundBlurRadius == mLastBackgroundBlurRadius
                 && mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
             return;
         }
 
         Drawable destDrawable = mOriginalBackgroundDrawable;
-        if (mWindow.mBackgroundBlurRadius > 0 && getViewRootImpl() != null
-                && mWindow.isTranslucent()) {
-            if (mBackgroundBlurDrawable == null) {
-                mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
-            }
+        if (mBackgroundBlurRadius > 0) {
             destDrawable = new LayerDrawable(new Drawable[] {mBackgroundBlurDrawable,
                                                              mOriginalBackgroundDrawable});
-            mLastBackgroundBlurRadius = mWindow.mBackgroundBlurRadius;
         }
 
-
         if (destDrawable != null && !mBackgroundInsets.equals(Insets.NONE)) {
             destDrawable = new InsetDrawable(destDrawable,
                     mBackgroundInsets.left, mBackgroundInsets.top,
@@ -1309,23 +1309,60 @@
         super.setBackgroundDrawable(destDrawable);
 
         mLastBackgroundInsets = mBackgroundInsets;
+        mLastBackgroundBlurRadius = mBackgroundBlurRadius;
         mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
     }
 
-    private void updateBackgroundBlur() {
+    private void updateBackgroundBlurCorners() {
         if (mBackgroundBlurDrawable == null) return;
 
+        float cornerRadius = 0;
         // If the blur radius is 0, the blur region won't be sent to surface flinger, so we don't
         // need to calculate the corner radius.
-        if (mWindow.mBackgroundBlurRadius > 0) {
-            if (mOriginalBackgroundDrawable != null) {
-                final Outline outline = new Outline();
-                mOriginalBackgroundDrawable.getOutline(outline);
-                mBackgroundBlurDrawable.setCornerRadius(outline.mMode == Outline.MODE_ROUND_RECT
-                                                           ? outline.getRadius() : 0);
-            }
+        if (mBackgroundBlurRadius != 0 && mOriginalBackgroundDrawable != null) {
+            final Outline outline = new Outline();
+            mOriginalBackgroundDrawable.getOutline(outline);
+            cornerRadius = outline.mMode == Outline.MODE_ROUND_RECT ? outline.getRadius() : 0;
         }
-        mBackgroundBlurDrawable.setBlurRadius(mWindow.mBackgroundBlurRadius);
+        mBackgroundBlurDrawable.setCornerRadius(cornerRadius);
+    }
+
+    private void updateBackgroundBlurRadius() {
+        if (getViewRootImpl() == null) return;
+
+        mBackgroundBlurRadius = mCrossWindowBlurEnabled && mWindow.isTranslucent()
+                ? mOriginalBackgroundBlurRadius : 0;
+        if (mBackgroundBlurDrawable == null && mBackgroundBlurRadius > 0) {
+            mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
+        }
+
+        if (mBackgroundBlurDrawable != null) {
+            mBackgroundBlurDrawable.setBlurRadius(mBackgroundBlurRadius);
+            updateBackgroundDrawable();
+        }
+    }
+
+    void setBackgroundBlurRadius(int blurRadius) {
+        mOriginalBackgroundBlurRadius = blurRadius;
+        if (blurRadius > 0) {
+            if (mCrossWindowBlurEnabledListener == null) {
+                mCrossWindowBlurEnabledListener = enabled -> {
+                    mCrossWindowBlurEnabled = enabled;
+                    updateBackgroundBlurRadius();
+                };
+                getContext().getSystemService(WindowManager.class)
+                        .addCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+                getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+            } else {
+                updateBackgroundBlurRadius();
+            }
+        } else if (mCrossWindowBlurEnabledListener != null) {
+            mCrossWindowBlurEnabledListener = null;
+            getContext().getSystemService(WindowManager.class)
+                    .removeCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+            getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+            updateBackgroundBlurRadius();
+        }
     }
 
     @Override
@@ -1758,9 +1795,6 @@
             cb.onAttachedToWindow();
         }
 
-        getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
-        updateBackgroundDrawable();
-
         if (mFeatureId == -1) {
             /*
              * The main window has been attached, try to restore any panels
@@ -1782,6 +1816,9 @@
             // renderer about it.
             mBackdropFrameRenderer.onConfigurationChange();
         }
+
+        updateBackgroundBlurRadius();
+
         mWindow.onViewRootImplSet(getViewRootImpl());
     }
 
@@ -1794,8 +1831,6 @@
             cb.onDetachedFromWindow();
         }
 
-        getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
-
         if (mWindow.mDecorContentParent != null) {
             mWindow.mDecorContentParent.dismissPopups();
         }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d06413c..6049486 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -75,6 +75,7 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.CrossWindowBlurListeners;
 import android.view.Gravity;
 import android.view.IRotationWatcher.Stub;
 import android.view.IScrollCaptureCallbacks;
@@ -258,7 +259,7 @@
     Drawable mBackgroundDrawable = null;
     Drawable mBackgroundFallbackDrawable = null;
 
-    int mBackgroundBlurRadius = 0;
+    private int mBackgroundBlurRadius = 0;
 
     private boolean mLoadElevation = true;
     private float mElevation;
@@ -1527,9 +1528,11 @@
     @Override
     public final void setBackgroundBlurRadius(int blurRadius) {
         super.setBackgroundBlurRadius(blurRadius);
-        if (getContext().getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_CROSS_LAYER_BLUR)) {
-            mBackgroundBlurRadius = Math.max(blurRadius, 0);
+        if (CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED) {
+            if (mBackgroundBlurRadius != Math.max(blurRadius, 0)) {
+                mBackgroundBlurRadius = Math.max(blurRadius, 0);
+                mDecor.setBackgroundBlurRadius(mBackgroundBlurRadius);
+            }
         }
     }
 
@@ -2556,8 +2559,8 @@
                 params.flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
             }
 
-            params.blurBehindRadius = a.getDimensionPixelSize(
-                    android.R.styleable.Window_windowBlurBehindRadius, 0);
+            params.setBlurBehindRadius(a.getDimensionPixelSize(
+                    android.R.styleable.Window_windowBlurBehindRadius, 0));
         }
 
         setBackgroundBlurRadius(a.getDimensionPixelSize(
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 8d82e33..c336373 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -35,8 +35,7 @@
  * {@hide}
  */
 oneway interface IInputMethod {
-    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps,
-             int configChanges);
+    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
     void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
             in IInlineSuggestionsRequestCallback cb);
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 1b1e0bf..8ecc809 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -32,7 +32,6 @@
 import android.app.RemoteInputHistoryItem;
 import android.content.Context;
 import android.content.res.ColorStateList;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.GradientDrawable;
@@ -62,11 +61,9 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
-import com.android.internal.graphics.ColorUtils;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 import java.util.Objects;
 import java.util.function.Consumer;
 
@@ -118,7 +115,6 @@
     private ViewGroup mExpandButtonAndContentContainer;
     private NotificationExpandButton mExpandButton;
     private MessagingLinearLayout mImageMessageContainer;
-    private int mExpandButtonExpandedTopMargin;
     private int mBadgedSideMargins;
     private int mConversationAvatarSize;
     private int mConversationAvatarSizeExpanded;
@@ -147,7 +143,6 @@
     private int mFacePileProtectionWidth;
     private int mFacePileProtectionWidthExpanded;
     private boolean mImportantConversation;
-    private TextView mUnreadBadge;
     private View mFeedbackIcon;
     private float mMinTouchSize;
     private Icon mConversationIcon;
@@ -245,8 +240,6 @@
         mContentContainer = findViewById(R.id.notification_action_list_margin_target);
         mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
         mExpandButton = findViewById(R.id.expand_button);
-        mExpandButtonExpandedTopMargin = getResources().getDimensionPixelSize(
-                R.dimen.conversation_expand_button_top_margin_expanded);
         mNotificationHeaderExpandedPadding = getResources().getDimensionPixelSize(
                 R.dimen.conversation_header_expanded_padding_end);
         mContentMarginEnd = getResources().getDimensionPixelSize(
@@ -286,7 +279,6 @@
         mAppName.setOnVisibilityChangedListener((visibility) -> {
             onAppNameVisibilityChanged();
         });
-        mUnreadBadge = findViewById(R.id.conversation_unread_count);
         mConversationContentStart = getResources().getDimensionPixelSize(
                 R.dimen.conversation_content_start);
         mInternalButtonPadding
@@ -426,17 +418,7 @@
 
     /** @hide */
     public void setUnreadCount(int unreadCount) {
-        boolean visible = mIsCollapsed && unreadCount > 1;
-        mUnreadBadge.setVisibility(visible ? VISIBLE : GONE);
-        if (visible) {
-            CharSequence text = unreadCount >= 100
-                    ? getResources().getString(R.string.unread_convo_overflow, 99)
-                    : String.format(Locale.getDefault(), "%d", unreadCount);
-            mUnreadBadge.setText(text);
-            mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor));
-            boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f;
-            mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE);
-        }
+        mExpandButton.setNumber(unreadCount);
     }
 
     private void addRemoteInputHistoryToMessages(
@@ -1132,15 +1114,16 @@
     }
 
     private void updateExpandButton() {
-        int gravity;
-        int topMargin = 0;
+        int buttonGravity;
+        int containerHeight;
         ViewGroup newContainer;
         if (mIsCollapsed) {
-            gravity = Gravity.CENTER;
+            buttonGravity = Gravity.CENTER;
+            containerHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
             newContainer = mExpandButtonAndContentContainer;
         } else {
-            gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-            topMargin = mExpandButtonExpandedTopMargin;
+            buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+            containerHeight = ViewGroup.LayoutParams.MATCH_PARENT;
             newContainer = this;
         }
         mExpandButton.setExpanded(!mIsCollapsed);
@@ -1149,14 +1132,14 @@
         // content when collapsed, but allows the content to flow under it when expanded.
         if (newContainer != mExpandButtonContainer.getParent()) {
             ((ViewGroup) mExpandButtonContainer.getParent()).removeView(mExpandButtonContainer);
+            mExpandButtonContainer.getLayoutParams().height = containerHeight;
             newContainer.addView(mExpandButtonContainer);
         }
 
         // update if the expand button is centered
         LinearLayout.LayoutParams layoutParams =
                 (LinearLayout.LayoutParams) mExpandButton.getLayoutParams();
-        layoutParams.gravity = gravity;
-        layoutParams.topMargin = topMargin;
+        layoutParams.gravity = buttonGravity;
         mExpandButton.setLayoutParams(layoutParams);
     }
 
@@ -1210,6 +1193,7 @@
             mExpandButtonContainer.setVisibility(GONE);
             mConversationIconContainer.setOnClickListener(null);
         }
+        mExpandButton.setVisibility(VISIBLE);
         updateContentEndPaddings();
     }
 
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 8add34f..fc4cc57 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -16,30 +16,42 @@
 
 package com.android.internal.widget;
 
-import static com.android.internal.widget.ColoredIconHelper.applyGrayTint;
-
+import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.RemotableViewMethod;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
+import android.widget.TextView;
 
 import com.android.internal.R;
 
+import java.util.Locale;
+
 /**
  * An expand button in a notification
  */
 @RemoteViews.RemoteView
-public class NotificationExpandButton extends ImageView {
+public class NotificationExpandButton extends FrameLayout {
 
-    private final int mMinTouchTargetSize;
+    private View mPillView;
+    private TextView mNumberView;
+    private ImageView mIconView;
     private boolean mExpanded;
-    private int mOriginalNotificationColor;
+    private int mNumber;
+    private int mDefaultPillColor;
+    private int mDefaultTextColor;
+    private int mHighlightPillColor;
+    private int mHighlightTextColor;
+    private boolean mDisallowColor;
 
     public NotificationExpandButton(Context context) {
         this(context, null, 0, 0);
@@ -57,7 +69,14 @@
     public NotificationExpandButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mMinTouchTargetSize = (int) (getResources().getDisplayMetrics().density * 48 + 0.5);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mPillView = findViewById(R.id.expand_button_pill);
+        mNumberView = findViewById(R.id.expand_button_number);
+        mIconView = findViewById(R.id.expand_button_icon);
     }
 
     /**
@@ -72,7 +91,6 @@
         } else {
             super.getBoundsOnScreen(outRect, clipToParent);
         }
-        extendRectToMinTouchSize(outRect);
     }
 
     /**
@@ -89,32 +107,12 @@
         return super.pointInView(localX, localY, slop);
     }
 
-    @RemotableViewMethod
-    public void setOriginalNotificationColor(int color) {
-        mOriginalNotificationColor = color;
-    }
-
-    public int getOriginalNotificationColor() {
-        return mOriginalNotificationColor;
-    }
-
     /**
-     * Set the button's color filter: to gray if true, otherwise colored.
-     * If this button has no original color, this has no effect.
+     * Disable the use of the accent colors for this view, if true.
      */
     public void setGrayedOut(boolean shouldApply) {
-        applyGrayTint(mContext, getDrawable(), shouldApply, mOriginalNotificationColor);
-    }
-
-    private void extendRectToMinTouchSize(Rect rect) {
-        if (rect.width() < mMinTouchTargetSize) {
-            rect.left = rect.centerX() - mMinTouchTargetSize / 2;
-            rect.right = rect.left + mMinTouchTargetSize;
-        }
-        if (rect.height() < mMinTouchTargetSize) {
-            rect.top = rect.centerY() - mMinTouchTargetSize / 2;
-            rect.bottom = rect.top + mMinTouchTargetSize;
-        }
+        mDisallowColor = shouldApply;
+        updateColors();
     }
 
     @Override
@@ -129,10 +127,10 @@
     @RemotableViewMethod
     public void setExpanded(boolean expanded) {
         mExpanded = expanded;
-        updateExpandButton();
+        updateExpandedState();
     }
 
-    private void updateExpandButton() {
+    private void updateExpandedState() {
         int drawableId;
         int contentDescriptionId;
         if (mExpanded) {
@@ -142,8 +140,89 @@
             drawableId = R.drawable.ic_expand_notification;
             contentDescriptionId = R.string.expand_button_content_description_collapsed;
         }
-        setImageDrawable(getContext().getDrawable(drawableId));
-        setColorFilter(mOriginalNotificationColor);
         setContentDescription(mContext.getText(contentDescriptionId));
+        mIconView.setImageDrawable(getContext().getDrawable(drawableId));
+
+        // changing the expanded state can affect the number display
+        updateNumber();
+    }
+
+    private void updateNumber() {
+        if (shouldShowNumber()) {
+            CharSequence text = mNumber >= 100
+                    ? getResources().getString(R.string.unread_convo_overflow, 99)
+                    : String.format(Locale.getDefault(), "%d", mNumber);
+            mNumberView.setText(text);
+            mNumberView.setVisibility(VISIBLE);
+        } else {
+            mNumberView.setVisibility(GONE);
+        }
+
+        // changing number can affect the color
+        updateColors();
+    }
+
+    private void updateColors() {
+        if (shouldShowNumber() && !mDisallowColor) {
+            mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+            mIconView.setColorFilter(mHighlightTextColor);
+            mNumberView.setTextColor(mHighlightTextColor);
+        } else {
+            mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+            mIconView.setColorFilter(mDefaultTextColor);
+            mNumberView.setTextColor(mDefaultTextColor);
+        }
+    }
+
+    private boolean shouldShowNumber() {
+        return !mExpanded && mNumber > 1;
+    }
+
+    /**
+     * Set the color used for the expand chevron and the text
+     */
+    @RemotableViewMethod
+    public void setDefaultTextColor(int color) {
+        mDefaultTextColor = color;
+        updateColors();
+    }
+
+    /**
+     * Sets the color used to for the expander when there is no number shown
+     */
+    @RemotableViewMethod
+    public void setDefaultPillColor(@ColorInt int color) {
+        mDefaultPillColor = color;
+        updateColors();
+    }
+
+    /**
+     * Set the color used for the expand chevron and the text
+     */
+    @RemotableViewMethod
+    public void setHighlightTextColor(int color) {
+        mHighlightTextColor = color;
+        updateColors();
+    }
+
+    /**
+     * Sets the color used to highlight the expander when there is a number shown
+     */
+    @RemotableViewMethod
+    public void setHighlightPillColor(@ColorInt int color) {
+        mHighlightPillColor = color;
+        updateColors();
+    }
+
+    /**
+     * Sets the number shown inside the expand button.
+     * This only appears when the expand button is collapsed, and when greater than 1.
+     */
+    @RemotableViewMethod
+    public void setNumber(int number) {
+        if (mNumber != number) {
+            mNumber = number;
+            updateNumber();
+        }
     }
 }
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 143017c..fd6038f 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -36,7 +36,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
-import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -60,9 +59,6 @@
      */
     private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
 
-    private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
-            SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
-
     public static class PointerState {
         // Trace of previous points.
         private float[] mTraceX = new float[32];
@@ -356,21 +352,6 @@
                     .toString(), 1 + itemW * 6, base, mTextPaint);
         }
 
-        int saveId = canvas.save();
-        if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
-            // Rotate negative (since we're rotating the drawing canvas vs the output).
-            canvas.rotate(-90.0f * mContext.getDisplay().getRotation());
-            switch (mContext.getDisplay().getRotation()) {
-                case Surface.ROTATION_90:
-                    canvas.translate(-canvas.getHeight(), 0);
-                    break;
-                case Surface.ROTATION_180:
-                    canvas.translate(-canvas.getWidth(), -canvas.getHeight());
-                    break;
-                case Surface.ROTATION_270:
-                    canvas.translate(0, -canvas.getWidth());
-            }
-        }
         // Pointer trace.
         for (int p = 0; p < NP; p++) {
             final PointerState ps = mPointers.get(p);
@@ -480,7 +461,6 @@
                 }
             }
         }
-        canvas.restoreToCount(saveId);
     }
 
     private void logMotionEvent(String type, MotionEvent event) {
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b40ffb0..bac6bbe 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -95,9 +95,6 @@
     // property for runtime configuration differentiation in vendor
     private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
 
-    // property for background blur support in surface flinger
-    private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
-
     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
     int[] mGlobalGids = EmptyArray.INT;
 
@@ -1237,8 +1234,7 @@
 
         final int incrementalVersion = IncrementalManager.getVersion();
         if (incrementalVersion > 0) {
-            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);
-            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY_VERSION, incrementalVersion);
+            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, incrementalVersion);
         }
 
         if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) {
@@ -1249,10 +1245,6 @@
             addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
         }
 
-        if (SystemProperties.get(BLUR_PROPERTY, "default").equals("1")) {
-            addFeature(PackageManager.FEATURE_CROSS_LAYER_BLUR, 0);
-        }
-
         if (SensorPrivacyManager.USE_MICROPHONE_TOGGLE) {
             addFeature(PackageManager.FEATURE_MICROPHONE_TOGGLE, 0);
         }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 2287900..d6d3387 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -51,6 +51,7 @@
         "android_util_XmlBlock.cpp",
         "android_util_jar_StrictJarFile.cpp",
         "com_android_internal_util_VirtualRefBasePtr.cpp",
+        ":deviceproductinfoconstants_aidl",
     ],
 
     include_dirs: [
@@ -150,7 +151,7 @@
                 "android_os_VintfRuntimeInfo.cpp",
                 "android_os_incremental_IncrementalManager.cpp",
                 "android_net_LocalSocketImpl.cpp",
-                "android_net_NetUtils.cpp",
+                "android_net_NetworkUtils.cpp",
                 "android_service_DataLoaderService.cpp",
                 "android_util_AssetManager.cpp",
                 "android_util_Binder.cpp",
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index c7439f1..b0c5751 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -83,6 +83,10 @@
     return true;
   }
 
+  std::optional<std::string_view> GetPath() const override {
+    return {};
+  }
+
   const std::string& GetDebugName() const override {
     return debug_name_;
   }
@@ -358,8 +362,16 @@
 }
 
 static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  return env->NewStringUTF(apk_assets->GetPath().c_str());
+  auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+  if (auto path = apk_assets->GetPath()) {
+    return env->NewStringUTF(path->data());
+  }
+  return nullptr;
+}
+
+static jstring NativeGetDebugName(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+  auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+  return env->NewStringUTF(apk_assets->GetDebugName().c_str());
 }
 
 static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
@@ -467,6 +479,7 @@
      (void*)NativeLoadFromFdOffset},
     {"nativeGetFinalizer", "()J", (void*)NativeGetFinalizer},
     {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
+    {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName},
     {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
     {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
     {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 8d193bf..0e0f98e 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -861,6 +861,23 @@
     return jStatus;
 }
 
+static void android_media_AudioRecord_setLogSessionId(JNIEnv *env, jobject thiz,
+                                                      jstring jlogSessionId) {
+    sp<AudioRecord> record = getAudioRecord(env, thiz);
+    if (record == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Unable to retrieve AudioRecord pointer for setLogSessionId()");
+    }
+    if (jlogSessionId == nullptr) {
+        ALOGV("%s: logSessionId nullptr", __func__);
+        record->setLogSessionId(nullptr);
+        return;
+    }
+    ScopedUtfChars logSessionId(env, jlogSessionId);
+    ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
+    record->setLogSessionId(logSessionId.c_str());
+}
+
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_get_port_id(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -876,50 +893,48 @@
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 static const JNINativeMethod gMethods[] = {
-    // name,               signature,  funcPtr
-    {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
-    {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
-                                      (void *)android_media_AudioRecord_setup},
-    {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
-    {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
-    {"native_read_in_byte_array",
-                             "([BIIZ)I",
-                                     (void *)android_media_AudioRecord_readInArray<jbyteArray>},
-    {"native_read_in_short_array",
-                             "([SIIZ)I",
-                                     (void *)android_media_AudioRecord_readInArray<jshortArray>},
-    {"native_read_in_float_array",
-                             "([FIIZ)I",
-                                     (void *)android_media_AudioRecord_readInArray<jfloatArray>},
-    {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
-                                       (void *)android_media_AudioRecord_readInDirectBuffer},
-    {"native_get_buffer_size_in_frames",
-                             "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
-    {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
-    {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
-    {"native_set_pos_update_period",
-                             "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
-    {"native_get_pos_update_period",
-                             "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
-    {"native_get_min_buff_size",
-                             "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
-    {"native_getMetrics",    "()Landroid/os/PersistableBundle;",
-                                         (void *)android_media_AudioRecord_native_getMetrics},
-    {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
-    {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
-    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
-    {"native_disableDeviceCallback", "()V",
-                                        (void *)android_media_AudioRecord_disableDeviceCallback},
-    {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
-                                       (void *)android_media_AudioRecord_get_timestamp},
-    {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
-                                        (void *)android_media_AudioRecord_get_active_microphones},
-    {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
-    {"native_set_preferred_microphone_direction", "(I)I",
-                        (void *)android_media_AudioRecord_set_preferred_microphone_direction},
-    {"native_set_preferred_microphone_field_dimension", "(F)I",
-                        (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
+        {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
+        {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
+        {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
+         (void *)android_media_AudioRecord_setup},
+        {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
+        {"native_release", "()V", (void *)android_media_AudioRecord_release},
+        {"native_read_in_byte_array", "([BIIZ)I",
+         (void *)android_media_AudioRecord_readInArray<jbyteArray>},
+        {"native_read_in_short_array", "([SIIZ)I",
+         (void *)android_media_AudioRecord_readInArray<jshortArray>},
+        {"native_read_in_float_array", "([FIIZ)I",
+         (void *)android_media_AudioRecord_readInArray<jfloatArray>},
+        {"native_read_in_direct_buffer", "(Ljava/lang/Object;IZ)I",
+         (void *)android_media_AudioRecord_readInDirectBuffer},
+        {"native_get_buffer_size_in_frames", "()I",
+         (void *)android_media_AudioRecord_get_buffer_size_in_frames},
+        {"native_set_marker_pos", "(I)I", (void *)android_media_AudioRecord_set_marker_pos},
+        {"native_get_marker_pos", "()I", (void *)android_media_AudioRecord_get_marker_pos},
+        {"native_set_pos_update_period", "(I)I",
+         (void *)android_media_AudioRecord_set_pos_update_period},
+        {"native_get_pos_update_period", "()I",
+         (void *)android_media_AudioRecord_get_pos_update_period},
+        {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
+        {"native_getMetrics", "()Landroid/os/PersistableBundle;",
+         (void *)android_media_AudioRecord_native_getMetrics},
+        {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
+        {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
+        {"native_enableDeviceCallback", "()V",
+         (void *)android_media_AudioRecord_enableDeviceCallback},
+        {"native_disableDeviceCallback", "()V",
+         (void *)android_media_AudioRecord_disableDeviceCallback},
+        {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
+         (void *)android_media_AudioRecord_get_timestamp},
+        {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
+         (void *)android_media_AudioRecord_get_active_microphones},
+        {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+        {"native_set_preferred_microphone_direction", "(I)I",
+         (void *)android_media_AudioRecord_set_preferred_microphone_direction},
+        {"native_set_preferred_microphone_field_dimension", "(F)I",
+         (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
+        {"native_setLogSessionId", "(Ljava/lang/String;)V",
+         (void *)android_media_AudioRecord_setLogSessionId},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index da60a75..cae6db5 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1426,8 +1426,13 @@
         jniThrowException(env, "java/lang/IllegalStateException",
                           "Unable to retrieve AudioTrack pointer for setLogSessionId()");
     }
+    if (jlogSessionId == nullptr) {
+        ALOGV("%s: logSessionId nullptr", __func__);
+        track->setLogSessionId(nullptr);
+        return;
+    }
     ScopedUtfChars logSessionId(env, jlogSessionId);
-    ALOGV("%s: logSessionId %s", __func__, logSessionId.c_str());
+    ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
     track->setLogSessionId(logSessionId.c_str());
 }
 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
similarity index 94%
rename from core/jni/android_net_NetUtils.cpp
rename to core/jni/android_net_NetworkUtils.cpp
index e2af87e..7508108 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "NetUtils"
+#define LOG_TAG "NetworkUtils"
 
 #include <vector>
 
@@ -123,15 +123,6 @@
     return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
 }
 
-static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
-{
-    return (jboolean) !protectFromVpn(socket);
-}
-
-static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
-    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
-}
-
 static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
 {
     return (jboolean) !queryUserAccess(uid, netId);
@@ -276,8 +267,6 @@
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
-    { "protectFromVpn", "(I)Z", (void*) android_net_utils_protectFromVpn },
-    { "protectFromVpn", "(Ljava/io/FileDescriptor;)Z", (void*) android_net_utils_protectFromVpnWithFd },
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
     { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 1c78750..5e142fd 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -45,6 +45,12 @@
     return value ? "true" : "false";
 }
 
+enum class HandleEventResponse : int {
+    // Allowed return values of 'handleEvent' function as documented in LooperCallback::handleEvent
+    REMOVE_CALLBACK = 0,
+    KEEP_CALLBACK = 1
+};
+
 static struct {
     jclass clazz;
 
@@ -70,6 +76,14 @@
     return str;
 }
 
+/**
+ * Convert an enumeration to its underlying type. Replace with std::to_underlying when available.
+ */
+template <class T>
+static std::underlying_type_t<T> toUnderlying(const T& t) {
+    return static_cast<std::underlying_type_t<T>>(t);
+}
+
 class NativeInputEventReceiver : public LooperCallback {
 public:
     NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak,
@@ -106,9 +120,16 @@
         return mInputConsumer.getChannel()->getName();
     }
 
-    virtual int handleEvent(int receiveFd, int events, void* data) override;
+    HandleEventResponse processOutboundEvents();
+    // From 'LooperCallback'
+    int handleEvent(int receiveFd, int events, void* data) override;
 };
 
+// Ensure HandleEventResponse underlying type matches the return type of LooperCallback::handleEvent
+static_assert(std::is_same<std::underlying_type_t<HandleEventResponse>,
+                           std::invoke_result_t<decltype(&LooperCallback::handleEvent),
+                                                NativeInputEventReceiver, int, int, void*>>::value);
+
 NativeInputEventReceiver::NativeInputEventReceiver(
         JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel,
         const sp<MessageQueue>& messageQueue)
@@ -179,10 +200,61 @@
     }
 }
 
+/**
+ * Receiver's primary role is to receive input events, but it has an additional duty of sending
+ * 'ack' for events (using the call 'finishInputEvent').
+ *
+ * If we are looking at the communication between InputPublisher and InputConsumer, we can say that
+ * from the InputConsumer's perspective, InputMessage's that are sent from publisher to consumer are
+ * called 'inbound / incoming' events, and the InputMessage's sent from InputConsumer to
+ * InputPublisher are 'outbound / outgoing' events.
+ *
+ * NativeInputEventReceiver owns (and acts like) an InputConsumer. So the finish events are outbound
+ * from InputEventReceiver (and will be sent to the InputPublisher).
+ *
+ * In this function, send as many events from 'mFinishQueue' as possible across the socket to the
+ * InputPublisher. If no events are remaining, let the looper know so that it doesn't wake up
+ * unnecessarily.
+ */
+HandleEventResponse NativeInputEventReceiver::processOutboundEvents() {
+    while (!mFinishQueue.empty()) {
+        const Finish& finish = *mFinishQueue.begin();
+        status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
+        if (status == OK) {
+            // Successful send. Erase the entry and keep trying to send more
+            mFinishQueue.erase(mFinishQueue.begin());
+            continue;
+        }
+
+        // Publisher is busy, try again later. Keep this entry (do not erase)
+        if (status == WOULD_BLOCK) {
+            if (kDebugDispatchCycle) {
+                ALOGD("channel '%s' ~ Remaining outbound events: %zu.",
+                      getInputChannelName().c_str(), mFinishQueue.size());
+            }
+            return HandleEventResponse::KEEP_CALLBACK; // try again later
+        }
+
+        // Some other error. Give up
+        ALOGW("Failed to send outbound event on channel '%s'.  status=%d",
+              getInputChannelName().c_str(), status);
+        if (status != DEAD_OBJECT) {
+            JNIEnv* env = AndroidRuntime::getJNIEnv();
+            std::string message =
+                    android::base::StringPrintf("Failed to send outbound event.  status=%d",
+                                                status);
+            jniThrowRuntimeException(env, message.c_str());
+            mMessageQueue->raiseAndClearException(env, "finishInputEvent");
+        }
+        return HandleEventResponse::REMOVE_CALLBACK;
+    }
+
+    // The queue is now empty. Tell looper there's no more output to expect.
+    setFdEvents(ALOOPER_EVENT_INPUT);
+    return HandleEventResponse::KEEP_CALLBACK;
+}
+
 int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
-    // Allowed return values of this function as documented in LooperCallback::handleEvent
-    constexpr int REMOVE_CALLBACK = 0;
-    constexpr int KEEP_CALLBACK = 1;
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
         // This error typically occurs when the publisher has closed the input channel
         // as part of removing a window or finishing an IME session, in which case
@@ -191,56 +263,25 @@
             ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                     "events=0x%x", getInputChannelName().c_str(), events);
         }
-        return REMOVE_CALLBACK;
+        return toUnderlying(HandleEventResponse::REMOVE_CALLBACK);
     }
 
     if (events & ALOOPER_EVENT_INPUT) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
         mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
-        return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
+        return status == OK || status == NO_MEMORY
+                ? toUnderlying(HandleEventResponse::KEEP_CALLBACK)
+                : toUnderlying(HandleEventResponse::REMOVE_CALLBACK);
     }
 
     if (events & ALOOPER_EVENT_OUTPUT) {
-        for (size_t i = 0; i < mFinishQueue.size(); i++) {
-            const Finish& finish = mFinishQueue[i];
-            status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
-            if (status != OK) {
-                mFinishQueue.erase(mFinishQueue.begin(), mFinishQueue.begin() + i);
-
-                if (status == WOULD_BLOCK) {
-                    if (kDebugDispatchCycle) {
-                        ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
-                              getInputChannelName().c_str(), i, mFinishQueue.size());
-                    }
-                    return KEEP_CALLBACK; // try again later
-                }
-
-                ALOGW("Failed to send finished signal on channel '%s'.  status=%d",
-                        getInputChannelName().c_str(), status);
-                if (status != DEAD_OBJECT) {
-                    JNIEnv* env = AndroidRuntime::getJNIEnv();
-                    std::string message =
-                            android::base::StringPrintf("Failed to finish input event.  status=%d",
-                                                        status);
-                    jniThrowRuntimeException(env, message.c_str());
-                    mMessageQueue->raiseAndClearException(env, "finishInputEvent");
-                }
-                return REMOVE_CALLBACK;
-            }
-        }
-        if (kDebugDispatchCycle) {
-            ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.",
-                    getInputChannelName().c_str(), mFinishQueue.size());
-        }
-        mFinishQueue.clear();
-        setFdEvents(ALOOPER_EVENT_INPUT);
-        return KEEP_CALLBACK;
+        return toUnderlying(processOutboundEvents());
     }
 
     ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
             "events=0x%x", getInputChannelName().c_str(), events);
-    return KEEP_CALLBACK;
+    return toUnderlying(HandleEventResponse::KEEP_CALLBACK);
 }
 
 status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 451ea93..cbf4481 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -27,6 +27,7 @@
 #include <android-base/chrono_utils.h>
 #include <android/graphics/region.h>
 #include <android/gui/BnScreenCaptureListener.h>
+#include <android/hardware/display/IDeviceProductInfoConstants.h>
 #include <android/os/IInputConstants.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -1022,16 +1023,24 @@
     } else {
         LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
     }
-    auto relativeAddress = env->NewIntArray(info->relativeAddress.size());
-    auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr);
-    for (int i = 0; i < info->relativeAddress.size(); i++) {
-        relativeAddressData[i] = info->relativeAddress[i];
+    jint connectionToSinkType;
+    // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing
+    // for a 5–device-deep hierarchy. For more information, refer:
+    // Section 8.7 - Physical Address of HDMI Specification Version 1.3a
+    using android::hardware::display::IDeviceProductInfoConstants;
+    if (info->relativeAddress.size() != 4) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
+    } else if (info->relativeAddress[0] == 0) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
+    } else if (info->relativeAddress[1] == 0) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT;
+    } else {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE;
     }
-    env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0);
 
     return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name,
                           manufacturerPnpId, productId, modelYear, manufactureDate,
-                          relativeAddress);
+                          connectionToSinkType);
 }
 
 static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1970,7 +1979,7 @@
                              "Ljava/lang/String;"
                              "Ljava/lang/Integer;"
                              "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;"
-                             "[I)V");
+                             "I)V");
 
     jclass deviceProductInfoManufactureDateClazz =
             FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate");
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
index 10fc18d..980e12d 100644
--- a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <android/file_descriptor_jni.h>
+
 #include "NetdClient.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
@@ -24,9 +26,20 @@
     setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
 }
 
+static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) {
+    return (jboolean)!protectFromVpn(socket);
+}
+
+static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
+    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
+}
+
 static const JNINativeMethod gNetworkUtilMethods[] = {
         {"setAllowNetworkingForProcess", "(Z)V",
          (void *)android_net_utils_setAllowNetworkingForProcess},
+        {"protectFromVpn", "(I)Z", (void *)android_net_utils_protectFromVpn},
+        {"protectFromVpn", "(Ljava/io/FileDescriptor;)Z",
+         (void *)android_net_utils_protectFromVpnWithFd},
 };
 
 int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv *env) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index c9062d8..bcfb06b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -304,15 +304,14 @@
 static FileDescriptorTable* gOpenFdTable = nullptr;
 
 // Must match values in com.android.internal.os.Zygote.
-// Note that there are gaps in the constants:
-// This is to further keep the values consistent with IVold.aidl
+// The values should be consistent with IVold.aidl
 enum MountExternalKind {
     MOUNT_EXTERNAL_NONE = 0,
     MOUNT_EXTERNAL_DEFAULT = 1,
-    MOUNT_EXTERNAL_INSTALLER = 5,
-    MOUNT_EXTERNAL_PASS_THROUGH = 7,
-    MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
-    MOUNT_EXTERNAL_COUNT = 9
+    MOUNT_EXTERNAL_INSTALLER = 2,
+    MOUNT_EXTERNAL_PASS_THROUGH = 3,
+    MOUNT_EXTERNAL_ANDROID_WRITABLE = 4,
+    MOUNT_EXTERNAL_COUNT = 5
 };
 
 // Must match values in com.android.internal.os.Zygote.
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 99fd215..e62b5c1 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -15,6 +15,7 @@
 ogunwale@google.com
 jjaggi@google.com
 roosa@google.com
+per-file package_item_info.proto = toddke@google.com
 per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
 per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c580b34..ad1d252 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -282,7 +282,8 @@
         optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto force_desktop_mode_on_external_displays = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Deprecated, use enable_non_resizable_multi_window
+        optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC, deprecated = true ];
         optional SettingProto enable_non_resizable_multi_window = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Development development = 39;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index ec502c3..f26bf7c 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -337,7 +337,7 @@
     optional bool starting_displayed = 20;
     optional bool starting_moved = 201;
     optional bool visible_set_from_transferred_starting_window = 22;
-    repeated .android.graphics.RectProto frozen_bounds = 23;
+    repeated .android.graphics.RectProto frozen_bounds = 23 [deprecated=true];
     optional bool visible = 24;
     reserved 25; // configuration_container
     optional IdentifierProto identifier = 26 [deprecated=true];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d5f5d28..072bb87 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1876,15 +1876,20 @@
     <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi @hide Allows system APK to update Wifi/Cellular coex channels to avoid.
+    <!-- @SystemApi @hide Allows applications to update Wifi/Cellular coex channels to avoid.
              <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|role" />
 
     <!-- @SystemApi @hide Allows applications to access Wifi/Cellular coex channels being avoided.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|role" />
+
+    <!-- @SystemApi @hide Allows system APK to manage country code.
+             <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_WIFI_COUNTRY_CODE"
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi @hide Allows an application to manage an automotive device's application network
          preference as it relates to OEM_PAID and OEM_PRIVATE capable networks.
@@ -2371,6 +2376,15 @@
     <permission android:name="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.telecom.CallDiagnosticService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.telecom.CallRedirectionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_primary_device_default_dark.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_primary_device_default_dark.xml
index 380dd85..90d6b07 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_primary_device_default_dark.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see primary_text_material_dark.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_50"/>
+    <item android:color="@color/system_primary_50"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_primary_device_default_light.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_primary_device_default_light.xml
index 380dd85..bdc4fa9 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_primary_device_default_light.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see primary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_900"/>
+    <item android:color="@color/system_primary_900"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_secondary_device_default_dark.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_secondary_device_default_dark.xml
index 380dd85..799636ad 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_secondary_device_default_dark.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see secondary_text_material_dark.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_200"/>
+    <item android:color="@color/system_primary_200"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_secondary_device_default_light.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_secondary_device_default_light.xml
index 380dd85..4793bb8 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_secondary_device_default_light.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see secondary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_700"/>
+    <item android:color="@color/system_primary_700"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_tertiary_device_default_dark.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_tertiary_device_default_dark.xml
index 380dd85..c828631 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_tertiary_device_default_dark.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see tertiary_text_material_dark.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_400"/>
+    <item android:color="@color/system_primary_400"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_tertiary_device_default_light.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_tertiary_device_default_light.xml
index 380dd85..82c420a 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_tertiary_device_default_light.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see tertiary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_500"/>
+    <item android:color="@color/system_primary_500"/>
+</selector>
diff --git a/core/res/res/drawable/conversation_unread_bg.xml b/core/res/res/drawable/expand_button_pill_bg.xml
similarity index 90%
rename from core/res/res/drawable/conversation_unread_bg.xml
rename to core/res/res/drawable/expand_button_pill_bg.xml
index d3e00cf..f95044a 100644
--- a/core/res/res/drawable/conversation_unread_bg.xml
+++ b/core/res/res/drawable/expand_button_pill_bg.xml
@@ -14,6 +14,6 @@
   ~ limitations under the License.
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <corners android:radius="20sp" />
+    <corners android:radius="@dimen/notification_expand_button_pill_height" />
     <solid android:color="@android:color/white" />
 </shape>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
index ca4f0ed..a06ec9f 100644
--- a/core/res/res/drawable/ic_collapse_notification.xml
+++ b/core/res/res/drawable/ic_collapse_notification.xml
@@ -21,8 +21,5 @@
     android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M18.59,16.41L20.0,15.0l-8.0,-8.0 -8.0,8.0 1.41,1.41L12.0,9.83"/>
-    <path
-        android:pathData="M0 0h24v24H0V0z"
-        android:fillColor="#00000000"/>
+        android:pathData="M18.59,15.41L20.0,14.0l-8.0,-8.0 -8.0,8.0 1.41,1.41L12.0,8.83"/>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
index a080ce4..160a9c2 100644
--- a/core/res/res/drawable/ic_expand_notification.xml
+++ b/core/res/res/drawable/ic_expand_notification.xml
@@ -21,8 +21,5 @@
     android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M5.41,7.59L4.0,9.0l8.0,8.0 8.0,-8.0 -1.41,-1.41L12.0,14.17"/>
-    <path
-        android:pathData="M24 24H0V0h24v24z"
-        android:fillColor="#00000000"/>
+        android:pathData="M5.41,8.59L4.0,10.0l8.0,8.0 8.0,-8.0 -1.41,-1.41L12.0,15.17"/>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_expand_button.xml b/core/res/res/layout/notification_expand_button.xml
new file mode 100644
index 0000000..f92e6d6
--- /dev/null
+++ b/core/res/res/layout/notification_expand_button.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2021 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
+  -->
+
+<com.android.internal.widget.NotificationExpandButton
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/expand_button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|end"
+    android:contentDescription="@string/expand_button_content_description_collapsed"
+    android:padding="16dp"
+    android:visibility="gone"
+    >
+
+    <LinearLayout
+        android:id="@+id/expand_button_pill"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/notification_expand_button_pill_height"
+        android:orientation="horizontal"
+        android:background="@drawable/expand_button_pill_bg"
+        >
+
+        <TextView
+            android:id="@+id/expand_button_number"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/notification_expand_button_pill_height"
+            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
+            android:gravity="center_vertical"
+            android:paddingLeft="8dp"
+            />
+
+        <ImageView
+            android:id="@+id/expand_button_icon"
+            android:layout_width="@dimen/notification_expand_button_pill_height"
+            android:layout_height="@dimen/notification_expand_button_pill_height"
+            android:padding="2dp"
+            android:scaleType="fitCenter"
+            android:importantForAccessibility="no"
+            />
+
+    </LinearLayout>
+
+</com.android.internal.widget.NotificationExpandButton>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 1de1d04..81a79c5 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -30,7 +30,8 @@
         android:id="@+id/left_icon"
         android:layout_width="@dimen/notification_left_icon_size"
         android:layout_height="@dimen/notification_left_icon_size"
-        android:layout_gravity="center_vertical|start"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
         android:layout_marginStart="@dimen/notification_left_icon_start"
         android:background="@drawable/notification_large_icon_outline"
         android:clipToOutline="true"
@@ -43,7 +44,8 @@
         android:id="@+id/icon"
         android:layout_width="@dimen/notification_icon_circle_size"
         android:layout_height="@dimen/notification_icon_circle_size"
-        android:layout_gravity="center_vertical|start"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
         android:layout_marginStart="@dimen/notification_icon_circle_start"
         android:background="@drawable/notification_icon_circle"
         android:padding="@dimen/notification_icon_circle_padding"
@@ -55,10 +57,12 @@
         android:id="@+id/notification_top_line"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_gravity="center_vertical"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_toStartOf="@id/expand_button"
+        android:layout_alignWithParentIfMissing="true"
         android:clipChildren="false"
         android:gravity="center_vertical"
-        android:paddingEnd="@dimen/notification_heading_margin_end"
         android:paddingStart="@dimen/notification_content_margin_start"
         android:theme="@style/Theme.DeviceDefault.Notification"
         >
@@ -71,19 +75,15 @@
         android:id="@+id/alternate_expand_target"
         android:layout_width="@dimen/notification_content_margin_start"
         android:layout_height="match_parent"
-        android:layout_gravity="start"
+        android:layout_alignParentStart="true"
         android:importantForAccessibility="no"
         />
 
-    <com.android.internal.widget.NotificationExpandButton
-        android:id="@+id/expand_button"
-        android:layout_width="@dimen/notification_header_expand_icon_size"
-        android:layout_height="@dimen/notification_header_expand_icon_size"
-        android:layout_gravity="center_vertical|end"
-        android:contentDescription="@string/expand_button_content_description_collapsed"
-        android:paddingTop="@dimen/notification_expand_button_padding_top"
-        android:scaleType="center"
-        android:visibility="gone"
+    <include layout="@layout/notification_expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
         />
 
 </NotificationHeaderView>
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index b83611bc..bad9a6b 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -74,14 +74,10 @@
         android:layout_height="match_parent"
         android:layout_gravity="end">
 
-        <com.android.internal.widget.NotificationExpandButton
-            android:id="@+id/expand_button"
-            android:layout_width="@dimen/notification_header_expand_icon_size"
-            android:layout_height="@dimen/notification_header_expand_icon_size"
+        <include layout="@layout/notification_expand_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/expand_button_content_description_collapsed"
-            android:paddingTop="@dimen/notification_expand_button_padding_top"
-            android:scaleType="center"
             />
 
     </FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_call.xml b/core/res/res/layout/notification_template_material_call.xml
index 471d874..7b52ec3 100644
--- a/core/res/res/layout/notification_template_material_call.xml
+++ b/core/res/res/layout/notification_template_material_call.xml
@@ -72,15 +72,10 @@
             </LinearLayout>
 
             <!-- TODO(b/179178086): remove padding from main column when this is visible -->
-            <com.android.internal.widget.NotificationExpandButton
-                android:id="@+id/expand_button"
-                android:layout_width="@dimen/notification_header_expand_icon_size"
-                android:layout_height="@dimen/notification_header_expand_icon_size"
+            <include layout="@layout/notification_expand_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
                 android:layout_gravity="top|end"
-                android:contentDescription="@string/expand_button_content_description_collapsed"
-                android:paddingTop="@dimen/notification_expand_button_padding_top"
-                android:scaleType="center"
-                android:visibility="gone"
                 />
 
         </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index f3aa540..42fb4a2 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -104,11 +104,10 @@
         <LinearLayout
             android:id="@+id/expand_button_touch_container"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/conversation_expand_button_size"
-            android:paddingStart="@dimen/conversation_expand_button_side_margin"
+            android:layout_height="@dimen/conversation_expand_button_height"
             android:orientation="horizontal"
             android:layout_gravity="end|top"
-            android:paddingEnd="@dimen/conversation_expand_button_side_margin"
+            android:paddingEnd="0dp"
             android:clipToPadding="false"
             android:clipChildren="false"
             >
@@ -118,34 +117,16 @@
                 android:forceHasOverlappingRendering="false"
                 android:layout_width="40dp"
                 android:layout_height="40dp"
-                android:layout_marginEnd="11dp"
+                android:layout_marginStart="@dimen/conversation_image_start_margin"
                 android:spacing="0dp"
                 android:layout_gravity="center"
                 android:clipToPadding="false"
                 android:clipChildren="false"
                 />
-            <!-- Unread Count -->
-            <TextView
-                android:id="@+id/conversation_unread_count"
-                android:layout_width="33sp"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="11dp"
-                android:layout_gravity="center"
-                android:gravity="center"
-                android:padding="2dp"
-                android:visibility="gone"
-                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
-                android:textColor="#FFFFFF"
-                android:textSize="12sp"
-                android:background="@drawable/conversation_unread_bg"
-                />
-            <com.android.internal.widget.NotificationExpandButton
-                android:id="@+id/expand_button"
+            <include layout="@layout/notification_expand_button"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
-                android:drawable="@drawable/ic_expand_notification"
-                android:contentDescription="@string/expand_button_content_description_collapsed"
                 />
         </LinearLayout>
     </FrameLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 735e1224..100983b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3564,16 +3564,6 @@
         <attr name="__removed2" format="boolean" />
         <!-- Specifies whether the IME supports showing inline suggestions. -->
         <attr name="supportsInlineSuggestions" format="boolean" />
-        <!-- Specify one or more configuration changes that the IME will handle itself. If not
-             specified, the IME will be restarted if any of these configuration changes happen in
-              the system.  Otherwise, the IME will remain running and its
-             {@link android.inputmethodservice.InputMethodService#onConfigurationChanged}
-             method is called with the new configuration.
-             <p>Note that all of these configuration changes can impact the
-             resource values seen by the application, so you will generally need
-             to re-retrieve all resources (including view layouts, drawables, etc)
-             to correctly handle any configuration change.-->
-        <attr name="configChanges" />
     </declare-styleable>
 
     <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 45e11ba..bed5c31 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1773,6 +1773,8 @@
             <enum name="maps" value="6" />
             <!-- Apps which are primarily productivity apps, such as cloud storage or workplace apps. -->
             <enum name="productivity" value="7" />
+            <!-- Apps which are primarily accessibility apps, such as screen-readers. -->
+            <enum name="accessibility" value="8" />
         </attr>
 
         <!-- Declares the kind of classloader this application's classes must be loaded with -->
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 1020c14..9b56321 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -42,12 +42,7 @@
     <color name="background_floating_device_default_dark">@color/system_primary_900</color>
     <color name="background_floating_device_default_light">@color/system_primary_100</color>
 
-    <color name="text_color_primary_device_default_light">@color/system_primary_900</color>
-    <color name="text_color_primary_device_default_dark">@color/system_primary_50</color>
-    <color name="text_color_secondary_device_default_light">@color/system_primary_700</color>
-    <color name="text_color_secondary_device_default_dark">@color/system_primary_200</color>
-    <color name="text_color_tertiary_device_default_light">@color/system_primary_500</color>
-    <color name="text_color_tertiary_device_default_dark">@color/system_primary_400</color>
+    <!-- Please refer to text_color_[primary]_device_default_[light].xml for text colors-->
     <color name="foreground_device_default_light">@color/text_color_primary_device_default_light</color>
     <color name="foreground_device_default_dark">@color/text_color_primary_device_default_dark</color>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 10164b0..633e216 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -673,15 +673,6 @@
         -->
     </integer-array>
 
-    <!-- The device states (supplied by DeviceStateManager) that should be treated as unfolded by
-         the display fold controller. Default is empty. -->
-    <integer-array name="config_unfoldedDeviceStates">
-        <!-- Example:
-        <item>3</item>
-        <item>4</item>
-        -->
-    </integer-array>
-
     <!-- Indicate the display area rect for foldable devices in folded state. -->
     <string name="config_foldedArea"></string>
 
@@ -857,6 +848,15 @@
         <!-- y-intercept --> <item>1.000000000000000</item>
     </string-array>
 
+    <!-- Default strength, in percentage, of bright color reduction when activated. -->
+    <integer name="config_reduceBrightColorsStrengthDefault">0</integer>
+
+    <!-- Minimum strength, in percentage, supported by bright color reduction. -->
+    <integer name="config_reduceBrightColorsStrengthMin">0</integer>
+
+    <!-- Maximum strength, in percentage, supported by bright color reduction. -->
+    <integer name="config_reduceBrightColorsStrengthMax">100</integer>
+
     <!-- Boolean indicating whether display white balance is supported. -->
     <bool name="config_displayWhiteBalanceAvailable">false</bool>
 
@@ -1792,7 +1792,7 @@
              * SDK level 28 makes the following algorithms mandatory : "cbc(aes)", "hmac(md5)",
                "hmac(sha1)", "hmac(sha256)", "hmac(sha384)", "hmac(sha512)", "rfc4106(gcm(aes))"
              * SDK level 31 makes the following algorithms mandatory : "rfc3686(ctr(aes))",
-               "xcbc(aes)", "rfc7539esp(chacha20,poly1305)"
+               "xcbc(aes)", "cmac(aes)", "rfc7539esp(chacha20,poly1305)"
      -->
     <string-array name="config_optionalIpSecAlgorithms" translatable="false">
         <!-- Add algorithm here -->
@@ -1964,6 +1964,8 @@
     <string name="config_systemContacts" translatable="false">com.android.contacts</string>
     <!-- The name of the package that will hold the speech recognizer role by default. -->
     <string name="config_systemSpeechRecognizer" translatable="false"></string>
+    <!-- The name of the package that will hold the system Wi-Fi coex manager role. -->
+    <string name="config_systemWifiCoexManager" translateable="false"></string>
 
     <!-- The name of the package that will be allowed to change its components' label/icon. -->
     <string name="config_overrideComponentUiPackage" translatable="false"></string>
@@ -3948,6 +3950,10 @@
          color supplied by the Notification.Builder if present. -->
     <bool name="config_tintNotificationActionButtons">true</bool>
 
+    <!-- Flag indicating that tinted items (actions, expander, etc) are to be tinted using the
+         theme color, rather than the notification color. -->
+    <bool name="config_tintNotificationsWithTheme">true</bool>
+
     <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
     <bool name="config_showAreaUpdateInfoSettings">false</bool>
 
@@ -4662,15 +4668,6 @@
     <!-- WindowsManager JetPack display features -->
     <string name="config_display_features" translatable="false" />
 
-    <!-- Physical Display IDs of the display-devices that are swapped when a folding device folds.
-         This list is expected to contain two elements: the first is the display to use
-         when the device is folded, the second is the display to use when unfolded. If the array
-         is empty or the display IDs are not recognized, this feature is turned off and the value
-         ignored.
-         TODO: b/170470621 - remove once we can have multiple Internal displays in DMS as
-               well as a notification from DisplayStateManager. -->
-    <string-array name="config_internalFoldedPhysicalDisplayIds" translatable="false" />
-
     <!-- Aspect ratio of task level letterboxing. Values <= 1.0 will be ignored.
          Note: Activity min/max aspect ratio restrictions will still be respected by the
          activity-level letterboxing (size-compat mode). Therefore this override can control the
@@ -4701,6 +4698,14 @@
     <!-- If true, hide the display cutout with display area -->
     <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
 
+    <!-- The timeout value in milliseconds used by SelectionActionModeHelper for each selections
+     when TextClassifier has been initialized. -->
+    <integer name="config_smartSelectionInitializedTimeoutMillis">200</integer>
+
+    <!-- The timeout value in milliseconds used by SelectionActionModeHelper for each selections
+         when TextClassifier has not been initialized. -->
+    <integer name="config_smartSelectionInitializingTimeoutMillis">500</integer>
+
     <!-- Indicates that default fitness tracker app needs to request sensor and location permissions. -->
     <bool name="config_trackerAppNeedsPermissions">false</bool>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c2b6b99..10aa7b3 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -224,7 +224,7 @@
     <dimen name="notification_content_margin_end">16dp</dimen>
 
     <!-- The margin on the end of the top-line content views (accommodates the expander) -->
-    <dimen name="notification_heading_margin_end">48dp</dimen>
+    <dimen name="notification_heading_margin_end">56dp</dimen>
 
     <!-- The margin for text at the end of the image view for media notifications -->
     <dimen name="notification_media_image_margin_end">72dp</dimen>
@@ -248,7 +248,7 @@
     <dimen name="call_notification_collapsible_indent">64dp</dimen>
 
     <!-- The size of icons for visual actions in the notification_material_action_list -->
-    <dimen name="notification_actions_icon_size">48dp</dimen>
+    <dimen name="notification_actions_icon_size">56dp</dimen>
 
     <!-- The size of icons for visual actions in the notification_material_action_list -->
     <dimen name="notification_actions_icon_drawable_size">20dp</dimen>
@@ -314,10 +314,10 @@
     <dimen name="notification_conversation_header_separating_margin">4dp</dimen>
 
     <!-- The absolute size of the notification expand icon. -->
-    <dimen name="notification_header_expand_icon_size">48dp</dimen>
+    <dimen name="notification_header_expand_icon_size">56dp</dimen>
 
-    <!-- The top padding for the notification expand button. -->
-    <dimen name="notification_expand_button_padding_top">1dp</dimen>
+    <!-- the height of the expand button pill -->
+    <dimen name="notification_expand_button_pill_height">24dp</dimen>
 
     <!-- Vertical margin for the headerless notification content, when content has 1 line -->
     <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
@@ -690,6 +690,13 @@
     <!-- The default minimal size of a PiP task, in both dimensions. -->
     <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
 
+    <!--
+      The overridable minimal size of a PiP task, in both dimensions.
+      Different from default_minimal_size_pip_resizable_task, this is to limit the dimension
+      when the pinned stack size is overridden by app via minWidth/minHeight.
+    -->
+    <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen>
+
     <!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
     <dimen name="task_height_of_minimized_mode">80dp</dimen>
 
@@ -739,7 +746,7 @@
     <dimen name="notification_right_icon_headerless_margin">20dp</dimen>
     <!-- The top margin of the right icon in the "big" notification states -->
     <!--  TODO(b/181048615): Move the large icon below the expander in big states  -->
-    <dimen name="notification_right_icon_big_margin_top">16dp</dimen>
+    <dimen name="notification_right_icon_big_margin_top">20dp</dimen>
     <!-- The size of the left icon -->
     <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
     <!-- The left padding of the left icon -->
@@ -770,13 +777,10 @@
     <dimen name="conversation_icon_circle_start">28dp</dimen>
     <!-- Start of the content in the conversation template -->
     <dimen name="conversation_content_start">80dp</dimen>
-    <!-- Size of the expand button in the conversation layout -->
-    <dimen name="conversation_expand_button_size">80dp</dimen>
-    <!-- Top margin of the expand button for conversations when expanded -->
-    <dimen name="conversation_expand_button_top_margin_expanded">18dp</dimen>
-    <!-- Side margin of the expand button for conversations.
-         width of expand asset (22) + 2 * this (13) == notification_header_expand_icon_size (48) -->
-    <dimen name="conversation_expand_button_side_margin">13dp</dimen>
+    <!-- Height of the expand button in the conversation layout -->
+    <dimen name="conversation_expand_button_height">80dp</dimen>
+    <!-- this is the margin between the Conversation image and the content -->
+    <dimen name="conversation_image_start_margin">12dp</dimen>
     <!-- Side margins of the conversation badge in relation to the conversation icon -->
     <dimen name="conversation_badge_side_margin">36dp</dimen>
     <!-- size of the notification badge when applied to the conversation icon -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2004d0a..9bc92e1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3168,6 +3168,8 @@
     <public name="config_customMediaSessionPolicyProvider" />
     <!-- @hide @SystemApi -->
     <public name="config_systemSpeechRecognizer" />
+    <!-- @hide @SystemApi -->
+    <public name="config_systemWifiCoexManager" />
   </public-group>
 
   <public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 71ba44b..2b1168f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1524,8 +1524,15 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
 
+    <!-- Name for an app setting that lets the user authenticate for that app using biometrics (e.g. fingerprint or face). [CHAR LIMIT=30] -->
+    <string name="biometric_app_setting_name">Use biometrics</string>
+    <!-- Name for an app setting that lets the user authenticate for that app using biometrics (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+    <string name="biometric_or_screen_lock_app_setting_name">Use biometrics or screen lock</string>
     <!-- Title shown when the system-provided biometric dialog is shown, asking the user to authenticate. [CHAR LIMIT=40] -->
     <string name="biometric_dialog_default_title">Verify it\u2019s you</string>
+    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] -->
+    <string name="biometric_dialog_default_subtitle">Use your biometric to continue</string>
+
     <!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
     <string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
     <!-- Message shown when biometric authentication was canceled by the user [CHAR LIMIT=50] -->
@@ -1539,6 +1546,11 @@
     <!-- Message returned to applications when an unexpected/unknown error occurs. [CHAR LIMIT=50]-->
     <string name="biometric_error_generic">Error authenticating</string>
 
+    <!-- Name for an app setting that lets the user authenticate for that app with their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=30] -->
+    <string name="screen_lock_app_setting_name">Use screen lock</string>
+    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+    <string name="screen_lock_dialog_default_subtitle">Enter your device credential to continue</string>
+
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
     <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
@@ -1585,6 +1597,11 @@
 
     <!-- Template to be used to name enrolled fingerprints by default. -->
     <string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
+
+    <!-- Name for an app setting that lets the user authenticate for that app with their fingerprint. [CHAR LIMIT=30] -->
+    <string name="fingerprint_app_setting_name">Use fingerprint</string>
+    <!-- Name for an app setting that lets the user authenticate for that app with their fingerprint or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+    <string name="fingerprint_or_screen_lock_app_setting_name">Use fingerprint or screen lock</string>
     <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their fingerprint. [CHAR LIMIT=70] -->
     <string name="fingerprint_dialog_default_subtitle">Use your fingerprint to continue</string>
 
@@ -1681,6 +1698,13 @@
     <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
     <string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
 
+    <!-- Name for an app setting that lets the user authenticate for that app with their face. [CHAR LIMIT=30] -->
+    <string name="face_app_setting_name">Use face unlock</string>
+    <!-- Name for an app setting that lets the user authenticate for that app with their face or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+    <string name="face_or_screen_lock_app_setting_name">Use face or screen lock</string>
+    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their face. [CHAR LIMIT=70] -->
+    <string name="face_dialog_default_subtitle">Use face unlock to continue</string>
+
     <!-- Array containing custom error messages from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="face_error_vendor">
     </string-array>
@@ -5193,6 +5217,8 @@
     <string name="app_category_maps">Maps &amp; Navigation</string>
     <!-- Category title for apps which are primarily productivity apps, such as cloud storage or workplace apps. [CHAR LIMIT=32] -->
     <string name="app_category_productivity">Productivity</string>
+    <!-- Category title for apps which are primarily accessibility apps, such as screen-readers. [CHAR LIMIT=32] -->
+    <string name="app_category_accessibility">Accessibility</string>
 
     <!-- Channel name for DeviceStorageMonitor notifications -->
     <string name="device_storage_monitor_notification_channel">Device storage</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8f07a2d..ff9d26f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -482,6 +482,8 @@
   <java-symbol type="array" name="config_integrityRuleProviderPackages" />
   <java-symbol type="bool" name="config_useAssistantVolume" />
   <java-symbol type="string" name="config_bandwidthEstimateSource" />
+  <java-symbol type="integer" name="config_smartSelectionInitializedTimeoutMillis" />
+  <java-symbol type="integer" name="config_smartSelectionInitializingTimeoutMillis" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
@@ -1893,6 +1895,7 @@
   <java-symbol type="bool" name="config_notificationHeaderClickableForExpand" />
   <java-symbol type="bool" name="config_enableNightMode" />
   <java-symbol type="bool" name="config_tintNotificationActionButtons" />
+  <java-symbol type="bool" name="config_tintNotificationsWithTheme" />
   <java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
   <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
@@ -1948,6 +1951,7 @@
   <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
   <java-symbol type="dimen" name="default_minimal_size_resizable_task" />
   <java-symbol type="dimen" name="default_minimal_size_pip_resizable_task" />
+  <java-symbol type="dimen" name="overridable_minimal_size_pip_resizable_task" />
   <java-symbol type="dimen" name="task_height_of_minimized_mode" />
   <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
   <java-symbol type="bool" name="config_allowPriorityVibrationsInLowPowerMode" />
@@ -2468,7 +2472,10 @@
   <java-symbol type="string" name="config_keyguardComponent" />
 
   <!-- Biometric messages -->
+  <java-symbol type="string" name="biometric_app_setting_name" />
+  <java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" />
   <java-symbol type="string" name="biometric_dialog_default_title" />
+  <java-symbol type="string" name="biometric_dialog_default_subtitle" />
   <java-symbol type="string" name="biometric_error_hw_unavailable" />
   <java-symbol type="string" name="biometric_error_user_canceled" />
   <java-symbol type="string" name="biometric_not_recognized" />
@@ -2476,6 +2483,10 @@
   <java-symbol type="string" name="biometric_error_device_not_secured" />
   <java-symbol type="string" name="biometric_error_generic" />
 
+  <!-- Device credential strings for BiometricManager -->
+  <java-symbol type="string" name="screen_lock_app_setting_name" />
+  <java-symbol type="string" name="screen_lock_dialog_default_subtitle" />
+
   <!-- Fingerprint messages -->
   <java-symbol type="string" name="fingerprint_error_unable_to_process" />
   <java-symbol type="string" name="fingerprint_error_hw_not_available" />
@@ -2493,6 +2504,8 @@
   <java-symbol type="string" name="fingerprint_error_lockout" />
   <java-symbol type="string" name="fingerprint_error_lockout_permanent" />
   <java-symbol type="string" name="fingerprint_name_template" />
+  <java-symbol type="string" name="fingerprint_app_setting_name" />
+  <java-symbol type="string" name="fingerprint_or_screen_lock_app_setting_name" />
   <java-symbol type="string" name="fingerprint_dialog_default_subtitle" />
   <java-symbol type="string" name="fingerprint_authenticated" />
   <java-symbol type="string" name="fingerprint_error_no_fingerprints" />
@@ -2540,6 +2553,9 @@
   <java-symbol type="string" name="face_acquired_sensor_dirty" />
   <java-symbol type="array" name="face_acquired_vendor" />
   <java-symbol type="string" name="face_name_template" />
+  <java-symbol type="string" name="face_app_setting_name" />
+  <java-symbol type="string" name="face_or_screen_lock_app_setting_name" />
+  <java-symbol type="string" name="face_dialog_default_subtitle" />
   <java-symbol type="string" name="face_authenticated_no_confirmation_required" />
   <java-symbol type="string" name="face_authenticated_confirmation_required" />
   <java-symbol type="string" name="face_error_security_update_required" />
@@ -2892,6 +2908,9 @@
   <java-symbol type="id" name="header_text" />
   <java-symbol type="id" name="header_text_secondary" />
   <java-symbol type="id" name="expand_button" />
+  <java-symbol type="id" name="expand_button_pill" />
+  <java-symbol type="id" name="expand_button_number" />
+  <java-symbol type="id" name="expand_button_icon" />
   <java-symbol type="id" name="alternate_expand_target" />
   <java-symbol type="id" name="notification_header" />
   <java-symbol type="id" name="notification_top_line" />
@@ -2912,7 +2931,6 @@
   <java-symbol type="dimen" name="notification_header_background_height" />
   <java-symbol type="dimen" name="notification_header_touchable_height" />
   <java-symbol type="dimen" name="notification_header_expand_icon_size" />
-  <java-symbol type="dimen" name="notification_expand_button_padding_top" />
   <java-symbol type="dimen" name="notification_header_icon_size" />
   <java-symbol type="dimen" name="notification_header_app_name_margin_start" />
   <java-symbol type="dimen" name="notification_header_separating_margin" />
@@ -3224,6 +3242,9 @@
   <java-symbol type="bool" name="config_reduceBrightColorsAvailable" />
   <java-symbol type="array" name="config_reduceBrightColorsCoefficients" />
   <java-symbol type="array" name="config_reduceBrightColorsCoefficientsNonlinear" />
+  <java-symbol type="integer" name="config_reduceBrightColorsStrengthDefault" />
+  <java-symbol type="integer" name="config_reduceBrightColorsStrengthMin" />
+  <java-symbol type="integer" name="config_reduceBrightColorsStrengthMax" />
   <java-symbol type="array" name="config_availableColorModes" />
   <java-symbol type="array" name="config_mappedColorModes" />
   <java-symbol type="string" name="config_vendorColorModesRestoreHint" />
@@ -3293,6 +3314,7 @@
   <java-symbol type="string" name="app_category_news" />
   <java-symbol type="string" name="app_category_maps" />
   <java-symbol type="string" name="app_category_productivity" />
+  <java-symbol type="string" name="app_category_accessibility" />
 
   <java-symbol type="raw" name="fallback_categories" />
 
@@ -3762,7 +3784,6 @@
 
   <!-- For Foldables -->
   <java-symbol type="array" name="config_foldedDeviceStates" />
-  <java-symbol type="array" name="config_unfoldedDeviceStates" />
   <java-symbol type="string" name="config_foldedArea" />
 
   <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
@@ -4030,7 +4051,6 @@
   <java-symbol type="id" name="message_icon_container" />
   <java-symbol type="id" name="conversation_image_message_container" />
   <java-symbol type="id" name="conversation_icon_container" />
-  <java-symbol type="dimen" name="conversation_expand_button_top_margin_expanded" />
   <java-symbol type="dimen" name="messaging_group_singleline_sender_padding_end" />
   <java-symbol type="dimen" name="conversation_badge_side_margin" />
   <java-symbol type="dimen" name="conversation_avatar_size" />
@@ -4051,7 +4071,6 @@
   <java-symbol type="dimen" name="button_padding_horizontal_material" />
   <java-symbol type="dimen" name="button_inset_horizontal_material" />
   <java-symbol type="layout" name="conversation_face_pile_layout" />
-  <java-symbol type="id" name="conversation_unread_count" />
   <java-symbol type="string" name="unread_convo_overflow" />
   <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" />
   <java-symbol type="drawable" name="conversation_badge_background" />
@@ -4158,7 +4177,6 @@
   <java-symbol type="dimen" name="default_background_blur_radius" />
   <java-symbol type="array" name="config_keep_warming_services" />
   <java-symbol type="string" name="config_display_features" />
-  <java-symbol type="array" name="config_internalFoldedPhysicalDisplayIds" />
 
   <java-symbol type="dimen" name="controls_thumbnail_image_max_height" />
   <java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 3706e4b..b0c1f25 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -24,6 +24,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
+import android.net.TetheringManager;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
@@ -141,7 +142,7 @@
         mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
         mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
         mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        mIntentFilter.addAction(TetheringManager.ACTION_TETHER_STATE_CHANGED);
         mContext.registerReceiver(mWifiReceiver, mIntentFilter);
 
         logv("Clear Wifi before we start the test.");
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 50b52eb..6c8b941 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -148,13 +148,15 @@
         PersistableBundle persistableBundle = new PersistableBundle();
         persistableBundle.putInt("k", 4);
         IBinder assistToken = new Binder();
+        IBinder shareableActivityToken = new Binder();
 
         Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder()
                 .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
                 .setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer)
                 .setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
                 .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
-                .setIsForward(true).setAssistToken(assistToken).build();
+                .setIsForward(true).setAssistToken(assistToken)
+                .setShareableActivityToken(shareableActivityToken).build();
 
         LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
         LaunchActivityItem item = itemSupplier.get();
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 02e75dd..1a06789e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -109,6 +109,7 @@
         private boolean mIsForward;
         private ProfilerInfo mProfilerInfo;
         private IBinder mAssistToken;
+        private IBinder mShareableActivityToken;
         private FixedRotationAdjustments mFixedRotationAdjustments;
 
         LaunchActivityItemBuilder setIntent(Intent intent) {
@@ -196,6 +197,11 @@
             return this;
         }
 
+        LaunchActivityItemBuilder setShareableActivityToken(IBinder shareableActivityToken) {
+            mShareableActivityToken = shareableActivityToken;
+            return this;
+        }
+
         LaunchActivityItemBuilder setFixedRotationAdjustments(FixedRotationAdjustments fra) {
             mFixedRotationAdjustments = fra;
             return this;
@@ -206,7 +212,8 @@
                     mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
                     mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
                     mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
-                    null /* activityClientController */, mFixedRotationAdjustments);
+                    null /* activityClientController */, mFixedRotationAdjustments,
+                    mShareableActivityToken);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index f6d985b..6f3d7ae 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -207,6 +207,7 @@
                 .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic())
                 .setPendingNewIntents(referrerIntentList()).setIsForward(true)
                 .setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments)
+                .setShareableActivityToken(new Binder())
                 .build();
 
         writeAndPrepareForReading(item);
diff --git a/core/tests/coretests/src/android/app/usage/OWNERS b/core/tests/coretests/src/android/app/usage/OWNERS
new file mode 100644
index 0000000..1271fa79
--- /dev/null
+++ b/core/tests/coretests/src/android/app/usage/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 532296
+include /services/usage/OWNERS
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
index 4d04a7a..8de9454 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
@@ -78,15 +78,15 @@
             "VALID_FLAG_BITS", "UNASSIGNED_TOKEN", "MAX_EVENT_TYPE"};
     // All fields in this list are final constants defining event types and not persisted
     private static final String[] EVENT_TYPES = {"NONE", "ACTIVITY_DESTROYED", "ACTIVITY_PAUSED",
-            "ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "CHOOSER_ACTION", "CONFIGURATION_CHANGE",
-            "CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE", "DEVICE_SHUTDOWN",
-            "DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK", "FOREGROUND_SERVICE_START",
-            "FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN", "KEYGUARD_SHOWN", "LOCUS_ID_SET",
-            "MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND", "NOTIFICATION_INTERRUPTION",
-            "NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE", "SCREEN_INTERACTIVE",
-            "SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED", "SLICE_PINNED_PRIV",
-            "STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION", "USER_STOPPED",
-            "USER_UNLOCKED"};
+            "ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "APP_COMPONENT_USED", "CHOOSER_ACTION",
+            "CONFIGURATION_CHANGE", "CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE",
+            "DEVICE_SHUTDOWN", "DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK",
+            "FOREGROUND_SERVICE_START", "FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN",
+            "KEYGUARD_SHOWN", "LOCUS_ID_SET", "MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND",
+            "NOTIFICATION_INTERRUPTION", "NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE",
+            "SCREEN_INTERACTIVE", "SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED",
+            "SLICE_PINNED_PRIV", "STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION",
+            "USER_STOPPED", "USER_UNLOCKED"};
 
     @Test
     public void testUsageEventsFields() {
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
index da92e69..ffe93bc 100644
--- a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
@@ -47,15 +47,16 @@
         final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW);
         final ShortcutInfo shortcut = new AppSearchShortcutInfo.Builder(id)
                 .setActivity(activity)
-                .setText(id)
+                .setLongLabel(id)
                 .setIconResName(shortcutIconResName)
                 .setIntent(shortcutIntent)
                 .setPerson(person)
                 .setCategories(categorySet)
                 .setFlags(ShortcutInfo.FLAG_LONG_LIVED)
                 .build()
-                .toShortcutInfo();
+                .toShortcutInfo(0);
 
+        assertThat(shortcut.getUserId()).isEqualTo(0);
         assertThat(shortcut.getId()).isEqualTo(id);
         assertThat(shortcut.getShortLabel()).isEqualTo(id);
         assertThat(shortcut.getIconResName()).isEqualTo(shortcutIconResName);
diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java
index eae41e3..7bc81cd 100644
--- a/core/tests/coretests/src/android/graphics/FontListParserTest.java
+++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java
@@ -26,6 +26,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static junit.framework.Assert.fail;
+
 import android.graphics.fonts.FontStyle;
 import android.os.LocaleList;
 import android.text.FontConfig;
@@ -44,6 +46,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
@@ -221,9 +224,113 @@
                 .that(readFamily(serialized)).isEqualTo(expected);
     }
 
+    @Test
+    public void invalidXml_unpaired_family() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='sans-serif'>"
+                + "    <font index='0'>test.ttc</font>"
+                + "</familyset>";
+
+        try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+            FontListParser.parse(is);
+            fail();
+        } catch (IOException | XmlPullParserException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void invalidXml_unpaired_font() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='sans-serif'>"
+                + "    <font index='0'>test.ttc"
+                + "  </family>"
+                + "</familyset>";
+
+        try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+            FontListParser.parse(is);
+            fail();
+        } catch (IOException | XmlPullParserException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void invalidXml_unpaired_axis() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='sans-serif'>"
+                + "    <font index='0'>test.ttc"
+                + "        <axis tag=\"wght\" styleValue=\"0\" >"
+                + "    </font>"
+                + "  </family>"
+                + "</familyset>";
+
+        try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+            FontListParser.parse(is);
+            fail();
+        } catch (IOException | XmlPullParserException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void invalidXml_unclosed_family() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='sans-serif'"
+                + "    <font index='0'>test.ttc</font>"
+                + "  </family>"
+                + "</familyset>";
+
+        try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+            FontListParser.parse(is);
+            fail();
+        } catch (IOException | XmlPullParserException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void invalidXml_unclosed_font() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='sans-serif'>"
+                + "    <font index='0'"
+                + "  </family>"
+                + "</familyset>";
+
+        try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+            FontListParser.parse(is);
+            fail();
+        } catch (IOException | XmlPullParserException e) {
+            // pass
+        }
+    }
+
+    @Test
+    public void invalidXml_unclosed_axis() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+                + "<familyset>"
+                + "  <family name='sans-serif'>"
+                + "    <font index='0'>test.ttc"
+                + "        <axis tag=\"wght\" styleValue=\"0\""
+                + "    </font>"
+                + "  </family>"
+                + "</familyset>";
+
+        try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+            FontListParser.parse(is);
+            fail();
+        } catch (IOException | XmlPullParserException e) {
+            // pass
+        }
+    }
+
     private FontConfig.FontFamily readFamily(String xml)
             throws IOException, XmlPullParserException {
-        StandardCharsets.UTF_8.name();
         ByteArrayInputStream buffer = new ByteArrayInputStream(
                 xml.getBytes(StandardCharsets.UTF_8));
         XmlPullParser parser = Xml.newPullParser();
diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
deleted file mode 100644
index 8906149..0000000
--- a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.inputmethodservice;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.rule.ServiceTestRule;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeoutException;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class InputMethodServiceTest {
-    private InputMethodService mService;
-    private Context mContext;
-    @Rule
-    public final ServiceTestRule serviceRule = new ServiceTestRule();
-
-    @Before
-    public void setUp() throws TimeoutException {
-        mContext = getInstrumentation().getContext();
-        mService = new InputMethodService();
-    }
-
-    @Test
-    public void testShouldImeRestartForConfig() throws Exception {
-        // Make sure we preserve Pre-S behavior i.e. Service restarts.
-        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
-        Configuration config = mContext.getResources().getConfiguration();
-        mService.setLastKnownConfig(config);
-        assertTrue("IME should restart for Pre-S",
-                mService.shouldImeRestartForConfig(config));
-
-        // IME shouldn't restart on targetSdk S+ (with no config changes).
-        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
-        assertFalse("IME shouldn't restart for S+",
-                mService.shouldImeRestartForConfig(config));
-
-        // Screen density changed but IME doesn't handle congfigChanges
-        config.densityDpi = 99;
-        assertTrue("IME should restart for unhandled configChanges",
-                mService.shouldImeRestartForConfig(config));
-
-        // opt-in IME to handle config changes.
-        mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY);
-        assertFalse("IME shouldn't restart for S+ since it handles configChanges",
-                mService.shouldImeRestartForConfig(config));
-    }
-}
diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java
index 8941190..c06405a 100644
--- a/core/tests/coretests/src/android/os/VibratorInfoTest.java
+++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java
@@ -20,6 +20,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import android.hardware.vibrator.IVibrator;
 import android.platform.test.annotations.Presubmit;
 
 import org.junit.Test;
@@ -33,16 +34,16 @@
     @Test
     public void testHasAmplitudeControl() {
         assertFalse(createInfo(/* capabilities= */ 0).hasAmplitudeControl());
-        assertTrue(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS
-                | VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL).hasAmplitudeControl());
+        assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS
+                | IVibrator.CAP_AMPLITUDE_CONTROL).hasAmplitudeControl());
     }
 
     @Test
     public void testHasCapabilities() {
-        assertTrue(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS)
-                .hasCapability(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS));
-        assertFalse(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS)
-                .hasCapability(VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL));
+        assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
+                .hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
+        assertFalse(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
+                .hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
     }
 
     @Test
@@ -59,7 +60,7 @@
 
     @Test
     public void testIsPrimitiveSupported() {
-        VibratorInfo info = new VibratorInfo(/* id= */ 0, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
+        VibratorInfo info = new VibratorInfo(/* id= */ 0, IVibrator.CAP_COMPOSE_EFFECTS,
                 null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
         assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
         assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
@@ -73,30 +74,30 @@
     @Test
     public void testEquals() {
         VibratorInfo empty = new VibratorInfo(1, 0, null, null);
-        VibratorInfo complete = new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+        VibratorInfo complete = new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
                 new int[]{VibrationEffect.EFFECT_CLICK},
                 new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
 
         assertEquals(complete, complete);
-        assertEquals(complete, new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+        assertEquals(complete, new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
                 new int[]{VibrationEffect.EFFECT_CLICK},
                 new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}));
 
         assertFalse(empty.equals(new VibratorInfo(1, 0, new int[]{}, new int[]{})));
-        assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
+        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
                 new int[]{VibrationEffect.EFFECT_CLICK},
                 new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
-        assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
                 new int[]{}, new int[]{})));
-        assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
                 null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
-        assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+        assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
                 new int[]{VibrationEffect.EFFECT_CLICK}, null)));
     }
 
     @Test
     public void testSerialization() {
-        VibratorInfo original = new VibratorInfo(1, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
+        VibratorInfo original = new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
                 new int[]{VibrationEffect.EFFECT_CLICK}, null);
 
         Parcel parcel = Parcel.obtain();
diff --git a/core/tests/coretests/src/android/view/accessibility/OWNERS b/core/tests/coretests/src/android/view/accessibility/OWNERS
new file mode 100644
index 0000000..b74281e
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
index 4680a64..ddb6729 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
@@ -17,14 +17,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.assist.ActivityId;
 import android.content.ComponentName;
+import android.os.Binder;
+import android.os.IBinder;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 /**
- * Unit test for {@link ContentCaptureEvent}.
+ * Unit test for {@link ContentCaptureContext}.
  *
  * <p>To run it:
  * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureContextTest}
@@ -35,13 +38,17 @@
     @Test
     public void testConstructorAdditionalFlags() {
         final ComponentName componentName = new ComponentName("component", "name");
+        final IBinder token = new Binder();
         final ContentCaptureContext ctx = new ContentCaptureContext(/* clientContext= */ null,
-                componentName, /* taskId= */ 666, /* displayId= */ 42, /* flags= */ 1);
+                new ActivityId(/* taskId= */ 666, token), componentName, /* displayId= */
+                42, /* flags= */ 1);
         final ContentCaptureContext newCtx = new ContentCaptureContext(ctx, /* extraFlags= */ 2);
         assertThat(newCtx.getFlags()).isEqualTo(3);
-
         assertThat(newCtx.getActivityComponent()).isEqualTo(componentName);
-        assertThat(newCtx.getTaskId()).isEqualTo(666);
+        ActivityId activityId = newCtx.getActivityId();
+        assertThat(activityId).isNotNull();
+        assertThat(activityId.getTaskId()).isEqualTo(666);
+        assertThat(activityId.getToken()).isEqualTo(token);
         assertThat(newCtx.getDisplayId()).isEqualTo(42);
         assertThat(newCtx.getExtras()).isNull();
         assertThat(newCtx.getLocusId()).isNull();
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index f7b5932..7748de5 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -28,6 +28,7 @@
     static_libs: [
         "androidx.test.rules",
         "frameworks-base-testutils",
+        "mockito-target-minus-junit4",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
new file mode 100644
index 0000000..dcef0a7
--- /dev/null
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.devicestate;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link DeviceStateInfo}.
+ * <p/>
+ * Run with <code>atest DeviceStateInfoTest</code>.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public final class DeviceStateInfoTest {
+    @Test
+    public void create() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int baseState = 0;
+        final int currentState = 2;
+
+        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertNotNull(info.supportedStates);
+        assertEquals(supportedStates, info.supportedStates);
+        assertEquals(baseState, info.baseState);
+        assertEquals(currentState, info.currentState);
+    }
+
+    @Test
+    public void equals() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int baseState = 0;
+        final int currentState = 2;
+
+        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertTrue(info.equals(info));
+
+        final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
+                currentState);
+        assertTrue(info.equals(sameInfo));
+
+        final DeviceStateInfo differentInfo = new DeviceStateInfo(new int[]{ 0, 2}, baseState,
+                currentState);
+        assertFalse(info.equals(differentInfo));
+    }
+
+    @Test
+    public void diff_sameObject() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int baseState = 0;
+        final int currentState = 2;
+
+        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertEquals(0, info.diff(info));
+    }
+
+    @Test
+    public void diff_differentSupportedStates() {
+        final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 0);
+        final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 2 }, 0, 0);
+        final int diff = info.diff(otherInfo);
+        assertTrue((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+    }
+
+    @Test
+    public void diff_differentNonOverrideState() {
+        final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 1, 0);
+        final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 2, 0);
+        final int diff = info.diff(otherInfo);
+        assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+        assertTrue((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+    }
+
+    @Test
+    public void diff_differentState() {
+        final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 1);
+        final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 0, 2);
+        final int diff = info.diff(otherInfo);
+        assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+        assertTrue((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+    }
+
+    @Test
+    public void writeToParcel() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int nonOverrideState = 0;
+        final int state = 2;
+        final DeviceStateInfo originalInfo =
+                new DeviceStateInfo(supportedStates, nonOverrideState, state);
+
+        final Parcel parcel = Parcel.obtain();
+        originalInfo.writeToParcel(parcel, 0 /* flags */);
+        parcel.setDataPosition(0);
+
+        final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
+        assertEquals(originalInfo, info);
+    }
+}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index e7fdfb8..79b4d8b 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,11 +16,15 @@
 
 package android.hardware.devicestate;
 
-import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import android.annotation.Nullable;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -32,6 +36,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -58,42 +63,75 @@
     }
 
     @Test
-    public void registerListener() {
-        mService.setBaseState(DEFAULT_DEVICE_STATE);
+    public void registerCallback() {
+        DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+        DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
 
-        TestDeviceStateListener listener1 = new TestDeviceStateListener();
-        TestDeviceStateListener listener2 = new TestDeviceStateListener();
-
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener1,
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
                 ConcurrentUtils.DIRECT_EXECUTOR);
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener2,
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2,
                 ConcurrentUtils.DIRECT_EXECUTOR);
-        assertEquals(DEFAULT_DEVICE_STATE, listener1.getLastReportedState().intValue());
-        assertEquals(DEFAULT_DEVICE_STATE, listener2.getLastReportedState().intValue());
 
+        // Verify initial callbacks
+        verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback1).onStateChanged(eq(mService.getMergedState()));
+        verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+        Mockito.reset(callback1);
+        Mockito.reset(callback2);
+
+        // Change the supported states and verify callback
+        mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE });
+        verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE });
+
+        Mockito.reset(callback1);
+        Mockito.reset(callback2);
+
+        // Change the base state and verify callback
         mService.setBaseState(OTHER_DEVICE_STATE);
-        assertEquals(OTHER_DEVICE_STATE, listener1.getLastReportedState().intValue());
-        assertEquals(OTHER_DEVICE_STATE, listener2.getLastReportedState().intValue());
+        verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback1).onStateChanged(eq(mService.getMergedState()));
+        verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+        Mockito.reset(callback1);
+        Mockito.reset(callback2);
+
+        // Change the requested state and verify callback
+        DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
+        mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
+
+        verify(callback1).onStateChanged(eq(mService.getMergedState()));
+        verify(callback2).onStateChanged(eq(mService.getMergedState()));
     }
 
     @Test
-    public void unregisterListener() {
-        mService.setBaseState(DEFAULT_DEVICE_STATE);
+    public void unregisterCallback() {
+        DeviceStateCallback callback = mock(DeviceStateCallback.class);
 
-        TestDeviceStateListener listener = new TestDeviceStateListener();
-
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                 ConcurrentUtils.DIRECT_EXECUTOR);
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
 
-        mDeviceStateManagerGlobal.unregisterDeviceStateListener(listener);
+        // Verify initial callbacks
+        verify(callback).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback).onStateChanged(eq(mService.getMergedState()));
+        Mockito.reset(callback);
 
+        mDeviceStateManagerGlobal.unregisterDeviceStateCallback(callback);
+
+        mService.setSupportedStates(new int[]{OTHER_DEVICE_STATE});
         mService.setBaseState(OTHER_DEVICE_STATE);
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+        verifyZeroInteractions(callback);
     }
 
     @Test
-    public void submittingRequestRegisteredCallback() {
+    public void submittingRequestRegistersCallback() {
         assertTrue(mService.mCallbacks.isEmpty());
 
         DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
@@ -104,37 +142,22 @@
 
     @Test
     public void submitRequest() {
-        mService.setBaseState(DEFAULT_DEVICE_STATE);
-
-        TestDeviceStateListener listener = new TestDeviceStateListener();
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+        DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                 ConcurrentUtils.DIRECT_EXECUTOR);
 
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+        verify(callback).onStateChanged(eq(mService.getBaseState()));
+        Mockito.reset(callback);
 
         DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
         mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
 
-        assertEquals(OTHER_DEVICE_STATE, listener.getLastReportedState().intValue());
+        verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
+        Mockito.reset(callback);
 
         mDeviceStateManagerGlobal.cancelRequest(request);
 
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
-    }
-
-    private final class TestDeviceStateListener implements DeviceStateManager.DeviceStateListener {
-        @Nullable
-        private Integer mLastReportedDeviceState;
-
-        @Override
-        public void onDeviceStateChanged(int deviceState) {
-            mLastReportedDeviceState = deviceState;
-        }
-
-        @Nullable
-        public Integer getLastReportedState() {
-            return mLastReportedDeviceState;
-        }
+        verify(callback).onStateChanged(eq(mService.getBaseState()));
     }
 
     private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
@@ -150,12 +173,34 @@
             }
         }
 
+        private int[] mSupportedStates = new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
         private int mBaseState = DEFAULT_DEVICE_STATE;
-        private int mMergedState = DEFAULT_DEVICE_STATE;
         private ArrayList<Request> mRequests = new ArrayList<>();
 
         private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
 
+        private DeviceStateInfo getInfo() {
+            final int mergedState = mRequests.isEmpty()
+                    ? mBaseState : mRequests.get(mRequests.size() - 1).state;
+            return new DeviceStateInfo(mSupportedStates, mBaseState, mergedState);
+        }
+
+        private void notifyDeviceStateInfoChanged() {
+            final DeviceStateInfo info = getInfo();
+            for (IDeviceStateManagerCallback callback : mCallbacks) {
+                try {
+                    callback.onDeviceStateInfoChanged(info);
+                } catch (RemoteException e) {
+                    // Do nothing. Should never happen.
+                }
+            }
+        }
+
+        @Override
+        public DeviceStateInfo getDeviceStateInfo() {
+            return getInfo();
+        }
+
         @Override
         public void registerCallback(IDeviceStateManagerCallback callback) {
             if (mCallbacks.contains(callback)) {
@@ -163,16 +208,6 @@
             }
 
             mCallbacks.add(callback);
-            try {
-                callback.onDeviceStateChanged(mMergedState);
-            } catch (RemoteException e) {
-                // Do nothing. Should never happen.
-            }
-        }
-
-        @Override
-        public int[] getSupportedDeviceStates() {
-            return new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
         }
 
         @Override
@@ -190,7 +225,7 @@
 
             final Request request = new Request(token, state, flags);
             mRequests.add(request);
-            notifyStateChangedIfNeeded();
+            notifyDeviceStateInfoChanged();
 
             for (IDeviceStateManagerCallback callback : mCallbacks) {
                 try {
@@ -223,32 +258,29 @@
                     // Do nothing. Should never happen.
                 }
             }
-            notifyStateChangedIfNeeded();
+            notifyDeviceStateInfoChanged();
+        }
+
+        public void setSupportedStates(int[] states) {
+            mSupportedStates = states;
+            notifyDeviceStateInfoChanged();
+        }
+
+        public int[] getSupportedStates() {
+            return mSupportedStates;
         }
 
         public void setBaseState(int state) {
             mBaseState = state;
-            notifyStateChangedIfNeeded();
+            notifyDeviceStateInfoChanged();
         }
 
-        private void notifyStateChangedIfNeeded() {
-            final int originalMergedState = mMergedState;
+        public int getBaseState() {
+            return mBaseState;
+        }
 
-            if (!mRequests.isEmpty()) {
-                mMergedState = mRequests.get(mRequests.size() - 1).state;
-            } else {
-                mMergedState = mBaseState;
-            }
-
-            if (mMergedState != originalMergedState) {
-                for (IDeviceStateManagerCallback callback : mCallbacks) {
-                    try {
-                        callback.onDeviceStateChanged(mMergedState);
-                    } catch (RemoteException e) {
-                        // Do nothing. Should never happen.
-                    }
-                }
-            }
+        public int getMergedState() {
+            return getInfo().currentState;
         }
     }
 }
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index d2b20b4..0808186 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -298,7 +298,7 @@
                     null /* pendingResults */, null /* pendingNewIntents */,
                     null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
                     mThread /* client */, null /* asssitToken */,
-                    null /* fixedRotationAdjustments */);
+                    null /* fixedRotationAdjustments */, null /* shareableActivityToken */);
         }
 
         @Override
diff --git a/data/etc/car/android.car.cluster.xml b/data/etc/car/android.car.cluster.xml
index d7f29da..de3acca 100644
--- a/data/etc/car/android.car.cluster.xml
+++ b/data/etc/car/android.car.cluster.xml
@@ -20,5 +20,7 @@
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+        <permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
+        <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.bugreport.xml b/data/etc/car/com.android.car.bugreport.xml
index c3642d88..2ff9835 100644
--- a/data/etc/car/com.android.car.bugreport.xml
+++ b/data/etc/car/com.android.car.bugreport.xml
@@ -21,5 +21,6 @@
         <permission name="android.permission.READ_LOGS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
+        <permission name="android.car.permission.CAR_DRIVING_STATE"/>
     </privapp-permissions>
   </permissions>
diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml
index 0e49284..ac16af3 100644
--- a/data/etc/car/com.android.car.carlauncher.xml
+++ b/data/etc/car/com.android.car.carlauncher.xml
@@ -17,9 +17,10 @@
 <permissions>
     <privapp-permissions package="com.android.car.carlauncher">
         <permission name="android.permission.ACTIVITY_EMBEDDING"/>
-	<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+        <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.dialer.xml b/data/etc/car/com.android.car.dialer.xml
index d44f5a1..61ae53a 100644
--- a/data/etc/car/com.android.car.dialer.xml
+++ b/data/etc/car/com.android.car.dialer.xml
@@ -18,5 +18,6 @@
     <privapp-permissions package="com.android.car.dialer">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.hvac.xml b/data/etc/car/com.android.car.hvac.xml
index d3631e0..534d44d 100644
--- a/data/etc/car/com.android.car.hvac.xml
+++ b/data/etc/car/com.android.car.hvac.xml
@@ -17,5 +17,6 @@
 <permissions>
     <privapp-permissions package="com.android.car.hvac">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.radio.xml b/data/etc/car/com.android.car.radio.xml
index d7853ab..ed8652c 100644
--- a/data/etc/car/com.android.car.radio.xml
+++ b/data/etc/car/com.android.car.radio.xml
@@ -18,5 +18,7 @@
     <privapp-permissions package="com.android.car.radio">
         <permission name="android.permission.ACCESS_BROADCAST_RADIO"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index bd30d7a..e6196c2 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -51,5 +51,41 @@
 
         <!-- use for rotary fragment to enable/disable packages related to rotary -->
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+
+        <!-- CarService permissions -->
+        <!-- TODO: Explain why so many permissions are required -->
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+        <permission name="android.car.permission.CAR_DIAGNOSTICS"/>
+        <permission name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
+        <permission name="android.car.permission.CAR_DRIVING_STATE"/>
+        <permission name="android.car.permission.CAR_DYNAMICS_STATE"/>
+        <permission name="android.car.permission.CAR_EXTERIOR_LIGHTS"/>
+        <permission name="android.car.permission.CAR_IDENTIFICATION"/>
+        <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+        <permission name="android.car.permission.CAR_MILEAGE"/>
+        <permission name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/>
+        <permission name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
+        <permission name="android.car.permission.CAR_POWER"/>
+        <permission name="android.car.permission.CAR_PROJECTION"/>
+        <permission name="android.car.permission.CAR_TIRES"/>
+        <permission name="android.car.permission.CAR_TEST_SERVICE"/>
+        <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/>
+        <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+        <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+        <permission name="android.car.permission.CONTROL_CAR_DOORS"/>
+        <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/>
+        <permission name="android.car.permission.CONTROL_CAR_FEATURES"/>
+        <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/>
+        <permission name="android.car.permission.CONTROL_CAR_SEATS"/>
+        <permission name="android.car.permission.CONTROL_CAR_WINDOWS"/>
+        <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"/>
+        <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"/>
+        <permission name="android.car.permission.READ_CAR_STEERING"/>
+        <permission name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"/>
+        <permission name="android.car.permission.STORAGE_MONITORING"/>
+        <permission name="android.car.permission.VMS_PUBLISHER"/>
+        <permission name="android.car.permission.VMS_SUBSCRIBER"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 3d964fb..f2a33de 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -70,5 +70,6 @@
         <permission name="android.permission.READ_WIFI_CREDENTIAL" />
         <permission name="android.permission.USE_BACKGROUND_BLUR" />
         <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
+        <permission name="android.permission.FORCE_STOP_PACKAGES" />
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index ea42246..77a38a9 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -166,6 +166,7 @@
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
     <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
     <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="audioserver" />
+    <assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="audioserver" />
 
     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
@@ -176,6 +177,7 @@
     <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="cameraserver" />
     <assign-permission name="android.permission.WATCH_APPOPS" uid="cameraserver" />
     <assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />
+    <assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="cameraserver" />
 
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 3900d7e..fae89d6 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -68,6 +68,11 @@
         <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.imsserviceentitlement">
+        <permission name="android.permission.MODIFY_PHONE_STATE" />
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.launcher3">
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
@@ -251,6 +256,7 @@
         <!-- Permissions required for reading DeviceConfig -->
         <permission name="android.permission.READ_DEVICE_CONFIG" />
         <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
+        <permission name="android.permission.MODIFY_QUIET_MODE"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.providers.telephony">
@@ -478,6 +484,8 @@
         <permission name="android.permission.SIGNAL_REBOOT_READINESS" />
         <!-- Permission required for CTS test - PeopleManagerTest -->
         <permission name="android.permission.READ_PEOPLE_DATA" />
+        <!-- Permission required for CTS test - UiTranslationManagerTest -->
+        <permission name="android.permission.MANAGE_UI_TRANSLATION" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index cabfad4..b7bf8ab 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -43,6 +43,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-2093859262": {
+      "message": "setClientVisible: %s clientVisible=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
     "-2072089308": {
       "message": "Attempted to add window with token that is a sub-window: %s.  Aborting.",
       "level": "WARN",
@@ -811,6 +817,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/Task.java"
     },
+    "-1159577965": {
+      "message": "Focus requested for input consumer=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
     "-1156118957": {
       "message": "Updated config=%s",
       "level": "DEBUG",
@@ -823,12 +835,6 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
     },
-    "-1144293044": {
-      "message": "SURFACE SET FREEZE LAYER: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
     "-1142279614": {
       "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
       "level": "VERBOSE",
@@ -1831,6 +1837,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "63329306": {
+      "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+    },
     "73987756": {
       "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
       "level": "INFO",
@@ -2461,6 +2473,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "691515534": {
+      "message": "  Commit wallpaper becoming invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
     "693423992": {
       "message": "setAnimationLocked: setting mFocusMayChange true",
       "level": "INFO",
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 4f188cc..66b8eae 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -245,7 +245,7 @@
     <alias name="monaco" to="monospace" />
 
     <family name="serif-monospace">
-        <font weight="400" style="normal">CutiveMono.ttf</font>
+        <font weight="400" style="normal">CutiveMono-Regular.ttf</font>
     </family>
     <alias name="courier" to="serif-monospace" />
     <alias name="courier new" to="serif-monospace" />
@@ -255,7 +255,7 @@
     </family>
 
     <family name="cursive">
-        <font weight="400" style="normal">DancingScript-Regular.ttf</font>
+        <font weight="400" style="normal">DancingScript.ttf</font>
         <font weight="700" style="normal">DancingScript-Bold.ttf</font>
     </family>
 
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index d1e94df..a927f53 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -36,11 +36,12 @@
 
 java_test_host {
     name: "error_prone_android_framework_test",
-    test_suites: ["general-tests"],
     srcs: ["tests/java/**/*.java"],
     java_resource_dirs: ["tests/res"],
     java_resources: [":error_prone_android_framework_testdata"],
     static_libs: [
+        "truth-prebuilt",
+        "kxml2-2.3.0",
         "error_prone_android_framework_lib",
         "error_prone_test_helpers",
         "hamcrest-library",
@@ -48,6 +49,9 @@
         "platform-test-annotations",
         "junit",
     ],
+    test_options: {
+        unit_test: true,
+    },
 }
 
 filegroup {
diff --git a/errorprone/TEST_MAPPING b/errorprone/TEST_MAPPING
deleted file mode 100644
index ee4552f..0000000
--- a/errorprone/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "presubmit": [
-        {
-            "name": "error_prone_android_framework_test"
-        }
-    ]
-}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 63df0db..95c7715 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -136,7 +136,7 @@
                 customization.getAdditionalNamedFamilies();
 
         parser.require(XmlPullParser.START_TAG, null, "familyset");
-        while (parser.next() != XmlPullParser.END_TAG) {
+        while (keepReading(parser)) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
@@ -158,6 +158,12 @@
         return new FontConfig(families, aliases, lastModifiedDate, configVersion);
     }
 
+    private static boolean keepReading(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int next = parser.next();
+        return next != XmlPullParser.END_TAG && next != XmlPullParser.END_DOCUMENT;
+    }
+
     /**
      * Read family tag in fonts.xml or oem_customization.xml
      */
@@ -168,7 +174,7 @@
         final String lang = parser.getAttributeValue("", "lang");
         final String variant = parser.getAttributeValue(null, "variant");
         final List<FontConfig.Font> fonts = new ArrayList<>();
-        while (parser.next() != XmlPullParser.END_TAG) {
+        while (keepReading(parser)) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             final String tag = parser.getName();
             if (tag.equals(TAG_FONT)) {
@@ -232,7 +238,7 @@
         boolean isItalic = STYLE_ITALIC.equals(parser.getAttributeValue(null, ATTR_STYLE));
         String fallbackFor = parser.getAttributeValue(null, ATTR_FALLBACK_FOR);
         StringBuilder filename = new StringBuilder();
-        while (parser.next() != XmlPullParser.END_TAG) {
+        while (keepReading(parser)) {
             if (parser.getEventType() == XmlPullParser.TEXT) {
                 filename.append(parser.getText());
             }
@@ -359,6 +365,8 @@
                 case XmlPullParser.END_TAG:
                     depth--;
                     break;
+                case XmlPullParser.END_DOCUMENT:
+                    return;
             }
         }
     }
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index f6f770b..da5162b 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -719,11 +719,11 @@
     /** @hide */
     public boolean stretch(float left, float top, float right, float bottom,
             float vecX, float vecY, float maxStretchAmount) {
-        if (1.0 < vecX || vecX < -1.0) {
-            throw new IllegalArgumentException("vecX must be in the range [-1, 1], was " + vecX);
+        if (Float.isInfinite(vecX) || Float.isNaN(vecX)) {
+            throw new IllegalArgumentException("vecX must be a finite, non-NaN value " + vecX);
         }
-        if (1.0 < vecY || vecY < -1.0) {
-            throw new IllegalArgumentException("vecY must be in the range [-1, 1], was " + vecY);
+        if (Float.isInfinite(vecY) || Float.isNaN(vecY)) {
+            throw new IllegalArgumentException("vecY must be a finite, non-NaN value " + vecY);
         }
         if (top >= bottom || left >= right) {
             throw new IllegalArgumentException(
@@ -734,7 +734,16 @@
             throw new IllegalArgumentException(
                     "The max stretch amount must be >0, got " + maxStretchAmount);
         }
-        return nStretch(mNativeRenderNode, left, top, right, bottom, vecX, vecY, maxStretchAmount);
+        return nStretch(
+                mNativeRenderNode,
+                left,
+                top,
+                right,
+                bottom,
+                vecX,
+                vecY,
+                maxStretchAmount
+        );
     }
 
     /**
diff --git a/keystore/java/android/security/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java
new file mode 100644
index 0000000..41cfb27
--- /dev/null
+++ b/keystore/java/android/security/LegacyVpnProfileStore.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.vpnprofilestore.IVpnProfileStore;
+import android.util.Log;
+
+/**
+ * @hide This class allows legacy VPN access to its profiles that were stored in Keystore.
+ * The storage of unstructured blobs in Android Keystore is going away, because there is no
+ * architectural or security benefit of storing profiles in keystore over storing them
+ * in the file system. This class allows access to the blobs that still exist in keystore.
+ * And it stores new blob in a database that is still owned by Android Keystore.
+ */
+public class LegacyVpnProfileStore {
+    private static final String TAG = "LegacyVpnProfileStore";
+
+    public static final int SYSTEM_ERROR = IVpnProfileStore.ERROR_SYSTEM_ERROR;
+    public static final int PROFILE_NOT_FOUND = IVpnProfileStore.ERROR_PROFILE_NOT_FOUND;
+
+    private static final String VPN_PROFILE_STORE_SERVICE_NAME = "android.security.vpnprofilestore";
+
+    private static IVpnProfileStore getService() {
+        return IVpnProfileStore.Stub.asInterface(
+                    ServiceManager.checkService(VPN_PROFILE_STORE_SERVICE_NAME));
+    }
+
+    /**
+     * Stores the profile under the alias in the profile database. Existing profiles by the
+     * same name will be replaced.
+     * @param alias The name of the profile
+     * @param profile The profile.
+     * @return true if the profile was successfully added. False otherwise.
+     * @hide
+     */
+    public static boolean put(@NonNull String alias, @NonNull byte[] profile) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                getService().put(alias, profile);
+                return true;
+            } else {
+                return KeyStore.getInstance().put(
+                        alias, profile, KeyStore.UID_SELF, 0);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to put vpn profile.", e);
+            return false;
+        }
+    }
+
+    /**
+     * Retrieves a profile by the name alias from the profile database.
+     * @param alias Name of the profile to retrieve.
+     * @return The unstructured blob, that is the profile that was stored using
+     *         LegacyVpnProfileStore#put or with
+     *         android.security.Keystore.put(Credentials.VPN + alias).
+     *         Returns null if no profile was found.
+     * @hide
+     */
+    public static byte[] get(@NonNull String alias) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                return getService().get(alias);
+            } else {
+                return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */);
+            }
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode != PROFILE_NOT_FOUND) {
+                Log.e(TAG, "Failed to get vpn profile.", e);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to get vpn profile.", e);
+        }
+        return null;
+    }
+
+    /**
+     * Removes a profile by the name alias from the profile database.
+     * @param alias Name of the profile to be removed.
+     * @return True if a profile was removed. False if no such profile was found.
+     * @hide
+     */
+    public static boolean remove(@NonNull String alias) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                getService().remove(alias);
+                return true;
+            } else {
+                return KeyStore.getInstance().delete(alias);
+            }
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode != PROFILE_NOT_FOUND) {
+                Log.e(TAG, "Failed to remove vpn profile.", e);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to remove vpn profile.", e);
+        }
+        return false;
+    }
+
+    /**
+     * Lists the vpn profiles stored in the database.
+     * @return An array of strings representing the aliases stored in the profile database.
+     *         The return value may be empty but never null.
+     * @hide
+     */
+    public static @NonNull String[] list(@NonNull String prefix) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                final String[] aliases = getService().list(prefix);
+                for (int i = 0; i < aliases.length; ++i) {
+                    aliases[i] = aliases[i].substring(prefix.length());
+                }
+                return aliases;
+            } else {
+                final String[] result = KeyStore.getInstance().list(prefix);
+                return result != null ? result : new String[0];
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to list vpn profiles.", e);
+        }
+        return new String[0];
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 7376d98..85bd24c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -24,7 +24,9 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
@@ -41,9 +43,11 @@
     private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
     private final Optional<SplitScreenController> mSplitScreenOptional;
     private final Optional<AppPairsController> mAppPairsOptional;
+    private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
     private final FullscreenTaskListener mFullscreenTaskListener;
     private final ShellExecutor mMainExecutor;
     private final Transitions mTransitions;
+    private final Optional<StartingSurface> mStartingSurfaceOptional;
 
     private final InitImpl mImpl = new InitImpl();
 
@@ -53,6 +57,8 @@
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
+            Optional<StartingSurface> startingSurfaceOptional,
+            Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
             ShellExecutor mainExecutor) {
@@ -62,6 +68,8 @@
                 legacySplitScreenOptional,
                 splitScreenOptional,
                 appPairsOptional,
+                startingSurfaceOptional,
+                pipTouchHandlerOptional,
                 fullscreenTaskListener,
                 transitions,
                 mainExecutor).mImpl;
@@ -73,6 +81,8 @@
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
+            Optional<StartingSurface> startingSurfaceOptional,
+            Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
             ShellExecutor mainExecutor) {
@@ -83,8 +93,10 @@
         mSplitScreenOptional = splitScreenOptional;
         mAppPairsOptional = appPairsOptional;
         mFullscreenTaskListener = fullscreenTaskListener;
+        mPipTouchHandlerOptional = pipTouchHandlerOptional;
         mTransitions = transitions;
         mMainExecutor = mainExecutor;
+        mStartingSurfaceOptional = startingSurfaceOptional;
     }
 
     private void init() {
@@ -93,6 +105,7 @@
 
         mShellTaskOrganizer.addListenerForType(
                 mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
+        mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
         // Register the shell organizer
         mShellTaskOrganizer.registerOrganizer();
 
@@ -105,6 +118,11 @@
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             mTransitions.register(mShellTaskOrganizer);
         }
+
+        // TODO(b/181599115): This should really be the pip controller, but until we can provide the
+        // controller instead of the feature interface, can just initialize the touch handler if
+        // needed
+        mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
     }
 
     @ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index efc55c4..9ddeb2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -44,7 +44,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+import com.android.wm.shell.startingsurface.StartingSurface;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -110,7 +110,7 @@
     private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>();
 
     private final Object mLock = new Object();
-    private final StartingSurfaceDrawer mStartingSurfaceDrawer;
+    private StartingSurface mStartingSurface;
 
     /**
      * In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -120,23 +120,19 @@
     private final SizeCompatUIController mSizeCompatUI;
 
     public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
-        this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
-                new StartingSurfaceDrawer(context, mainExecutor));
+        this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */);
     }
 
     public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
             SizeCompatUIController sizeCompatUI) {
-        this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
-                new StartingSurfaceDrawer(context, mainExecutor));
+        this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI);
     }
 
     @VisibleForTesting
     ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
-            Context context, @Nullable SizeCompatUIController sizeCompatUI,
-            StartingSurfaceDrawer startingSurfaceDrawer) {
+            Context context, @Nullable SizeCompatUIController sizeCompatUI) {
         super(taskOrganizerController, mainExecutor);
         mSizeCompatUI = sizeCompatUI;
-        mStartingSurfaceDrawer = startingSurfaceDrawer;
     }
 
     @Override
@@ -163,6 +159,15 @@
     }
 
     /**
+     * @hide
+     */
+    public void initStartingSurface(StartingSurface startingSurface) {
+        synchronized (mLock) {
+            mStartingSurface = startingSurface;
+        }
+    }
+
+    /**
      * Adds a listener for a specific task id.
      */
     public void addListenerForTaskId(TaskListener listener, int taskId) {
@@ -254,17 +259,23 @@
 
     @Override
     public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
-        mStartingSurfaceDrawer.addStartingWindow(info, appToken);
+        if (mStartingSurface != null) {
+            mStartingSurface.addStartingWindow(info, appToken);
+        }
     }
 
     @Override
     public void removeStartingWindow(int taskId) {
-        mStartingSurfaceDrawer.removeStartingWindow(taskId);
+        if (mStartingSurface != null) {
+            mStartingSurface.removeStartingWindow(taskId);
+        }
     }
 
     @Override
     public void copySplashScreenView(int taskId) {
-        mStartingSurfaceDrawer.copySplashScreenView(taskId);
+        if (mStartingSurface != null) {
+            mStartingSurface.copySplashScreenView(taskId);
+        }
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 5992447..46884fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -157,6 +157,7 @@
         });
         options.setLaunchCookie(launchCookie);
         options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        options.setRemoveWithTaskOrganizer(true);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 1320780..d31e637b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -327,6 +327,10 @@
         return mImpl;
     }
 
+    public ShellExecutor getMainExecutor() {
+        return mMainExecutor;
+    }
+
     /**
      * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 2f31acd..9ef3fb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -340,7 +340,7 @@
             mSettingsIcon.setVisibility(GONE);
         } else {
             mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
-            mTaskView.setListener(mContext.getMainExecutor(), mTaskViewListener);
+            mTaskView.setListener(mController.getMainExecutor(), mTaskViewListener);
             mExpandedViewContainer.addView(mTaskView);
             bringChildToFront(mTaskView);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 7d5c9f0..57a2b6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -227,29 +227,30 @@
     /*
      * Fade animation for consecutive flyouts.
      */
-    void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos) {
+    void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos,
+            boolean hideDot) {
         final Runnable afterFadeOut = () -> {
             updateFlyoutMessage(flyoutMessage, parentWidth);
             // Wait for TextViews to layout with updated height.
             post(() -> {
-                fade(true /* in */, stackPos, () -> {} /* after */);
+                fade(true /* in */, stackPos, hideDot, () -> {} /* after */);
             } /* after */ );
         };
-        fade(false /* in */, stackPos, afterFadeOut);
+        fade(false /* in */, stackPos, hideDot, afterFadeOut);
     }
 
     /*
      * Fade-out above or fade-in from below.
      */
-    private void fade(boolean in, PointF stackPos, Runnable afterFade) {
+    private void fade(boolean in, PointF stackPos, boolean hideDot, Runnable afterFade) {
         mFlyoutY = stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
 
         setAlpha(in ? 0f : 1f);
         setTranslationY(in ? mFlyoutY + FLYOUT_FADE_Y : mFlyoutY);
-        mRestingTranslationX = mArrowPointingLeft
-                ? stackPos.x + mBubbleSize + mFlyoutSpaceFromBubble
-                : stackPos.x - getWidth() - mFlyoutSpaceFromBubble;
+        updateFlyoutX(stackPos.x);
         setTranslationX(mRestingTranslationX);
+        updateDot(stackPos, hideDot);
+
         animate()
                 .alpha(in ? 1f : 0f)
                 .setDuration(in ? FLYOUT_FADE_IN_DURATION : FLYOUT_FADE_OUT_DURATION)
@@ -292,6 +293,33 @@
         mMessageText.setText(flyoutMessage.message);
     }
 
+    void updateFlyoutX(float stackX) {
+        // Calculate the translation required to position the flyout next to the bubble stack,
+        // with the desired padding.
+        mRestingTranslationX = mArrowPointingLeft
+                ? stackX + mBubbleSize + mFlyoutSpaceFromBubble
+                : stackX - getWidth() - mFlyoutSpaceFromBubble;
+    }
+
+    void updateDot(PointF stackPos, boolean hideDot) {
+        // Calculate the difference in size between the flyout and the 'dot' so that we can
+        // transform into the dot later.
+        final float newDotSize = hideDot ? 0f : mNewDotSize;
+        mFlyoutToDotWidthDelta = getWidth() - newDotSize;
+        mFlyoutToDotHeightDelta = getHeight() - newDotSize;
+
+        // Calculate the translation values needed to be in the correct 'new dot' position.
+        final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
+        final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
+        final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
+
+        final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
+        final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
+
+        mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
+        mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
+    }
+
     /** Configures the flyout, collapsed into dot form. */
     void setupFlyoutStartingAsDot(
             Bubble.FlyoutMessage flyoutMessage,
@@ -327,29 +355,8 @@
             mFlyoutY =
                     stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
             setTranslationY(mFlyoutY);
-
-            // Calculate the translation required to position the flyout next to the bubble stack,
-            // with the desired padding.
-            mRestingTranslationX = mArrowPointingLeft
-                    ? stackPos.x + mBubbleSize + mFlyoutSpaceFromBubble
-                    : stackPos.x - getWidth() - mFlyoutSpaceFromBubble;
-
-            // Calculate the difference in size between the flyout and the 'dot' so that we can
-            // transform into the dot later.
-            final float newDotSize = hideDot ? 0f : mNewDotSize;
-            mFlyoutToDotWidthDelta = getWidth() - newDotSize;
-            mFlyoutToDotHeightDelta = getHeight() - newDotSize;
-
-            // Calculate the translation values needed to be in the correct 'new dot' position.
-            final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
-            final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
-            final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
-
-            final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
-            final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
-
-            mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
-            mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
+            updateFlyoutX(stackPos.x);
+            updateDot(stackPos, hideDot);
             if (onLayoutComplete != null) {
                 onLayoutComplete.run();
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index e99669f5..78820a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -2431,7 +2431,7 @@
 
             if (mFlyout.getVisibility() == View.VISIBLE) {
                 mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
-                        mStackAnimationController.getStackPosition());
+                        mStackAnimationController.getStackPosition(), !bubble.showDot());
             } else {
                 mFlyout.setVisibility(INVISIBLE);
                 mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index ac5d14c..702385e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -54,6 +54,7 @@
     private float mMaxAspectRatio;
     private int mDefaultStackGravity;
     private int mDefaultMinSize;
+    private int mOverridableMinSize;
     private Point mScreenEdgeInsets;
 
     public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState) {
@@ -78,6 +79,8 @@
                 com.android.internal.R.integer.config_defaultPictureInPictureGravity);
         mDefaultMinSize = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+        mOverridableMinSize = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.overridable_minimal_size_pip_resizable_task);
         final String screenEdgeInsetsDpString = res.getString(
                 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
         final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
@@ -155,7 +158,10 @@
         // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout>
         // without minWidth/minHeight
         if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) {
-            return new Size(windowLayout.minWidth, windowLayout.minHeight);
+            // If either dimension is smaller than the allowed minimum, adjust them
+            // according to mOverridableMinSize
+            return new Size(Math.max(windowLayout.minWidth, mOverridableMinSize),
+                    Math.max(windowLayout.minHeight, mOverridableMinSize));
         }
         return null;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index d9a7bdb..9ee6a22 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -87,7 +87,7 @@
                     SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
 
     // Allow dragging the PIP to a location to close it
-    private final boolean mEnableDismissDragToEdge;
+    private boolean mEnableDismissDragToEdge;
 
     private int mDismissAreaHeight;
 
@@ -104,67 +104,66 @@
         mMotionHelper = motionHelper;
         mMainExecutor = mainExecutor;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+    }
 
-        Resources res = context.getResources();
+    public void init() {
+        Resources res = mContext.getResources();
         mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge);
         mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
 
-        mMainExecutor.execute(() -> {
-            mTargetView = new DismissCircleView(context);
-            mTargetViewContainer = new FrameLayout(context);
-            mTargetViewContainer.setBackgroundDrawable(
-                    context.getDrawable(R.drawable.floating_dismiss_gradient_transition));
-            mTargetViewContainer.setClipChildren(false);
-            mTargetViewContainer.addView(mTargetView);
+        mTargetView = new DismissCircleView(mContext);
+        mTargetViewContainer = new FrameLayout(mContext);
+        mTargetViewContainer.setBackgroundDrawable(
+                mContext.getDrawable(R.drawable.floating_dismiss_gradient_transition));
+        mTargetViewContainer.setClipChildren(false);
+        mTargetViewContainer.addView(mTargetView);
 
-            mMagnetizedPip = mMotionHelper.getMagnetizedPip();
-            mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
-            updateMagneticTargetSize();
+        mMagnetizedPip = mMotionHelper.getMagnetizedPip();
+        mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
+        updateMagneticTargetSize();
 
-            mMagnetizedPip.setAnimateStuckToTarget(
-                    (target, velX, velY, flung, after) -> {
-                        if (mEnableDismissDragToEdge) {
-                            mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung,
-                                    after);
-                        }
-                        return Unit.INSTANCE;
-                    });
-            mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
-                @Override
-                public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                    // Show the dismiss target, in case the initial touch event occurred within
-                    // the magnetic field radius.
+        mMagnetizedPip.setAnimateStuckToTarget(
+                (target, velX, velY, flung, after) -> {
                     if (mEnableDismissDragToEdge) {
-                        showDismissTargetMaybe();
+                        mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after);
                     }
+                    return Unit.INSTANCE;
+                });
+        mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
+            @Override
+            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+                // Show the dismiss target, in case the initial touch event occurred within
+                // the magnetic field radius.
+                if (mEnableDismissDragToEdge) {
+                    showDismissTargetMaybe();
                 }
+            }
 
-                @Override
-                public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
-                        float velX, float velY, boolean wasFlungOut) {
-                    if (wasFlungOut) {
-                        mMotionHelper.flingToSnapTarget(velX, velY, null /* endAction */);
-                        hideDismissTargetMaybe();
-                    } else {
-                        mMotionHelper.setSpringingToTouch(true);
-                    }
+            @Override
+            public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+                    float velX, float velY, boolean wasFlungOut) {
+                if (wasFlungOut) {
+                    mMotionHelper.flingToSnapTarget(velX, velY, null /* endAction */);
+                    hideDismissTargetMaybe();
+                } else {
+                    mMotionHelper.setSpringingToTouch(true);
                 }
+            }
 
-                @Override
-                public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                    mMainExecutor.executeDelayed(() -> {
-                        mMotionHelper.notifyDismissalPending();
-                        mMotionHelper.animateDismiss();
-                        hideDismissTargetMaybe();
+            @Override
+            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+                mMainExecutor.executeDelayed(() -> {
+                    mMotionHelper.notifyDismissalPending();
+                    mMotionHelper.animateDismiss();
+                    hideDismissTargetMaybe();
 
-                        mPipUiEventLogger.log(
-                                PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
-                    }, 0);
-                }
-            });
-
-            mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
+                    mPipUiEventLogger.log(
+                            PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
+                }, 0);
+            }
         });
+
+        mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index eae8945..d742aa6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -102,7 +102,7 @@
      * PhysicsAnimator instance for animating {@link PipBoundsState#getMotionBoundsState()}
      * using physics animations.
      */
-    private final PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator;
+    private PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator;
 
     private MagnetizedObject<Rect> mMagnetizedPip;
 
@@ -171,7 +171,7 @@
     public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
             PipTaskOrganizer pipTaskOrganizer, PhonePipMenuController menuController,
             PipSnapAlgorithm snapAlgorithm, PipTransitionController pipTransitionController,
-            FloatingContentCoordinator floatingContentCoordinator, ShellExecutor mainExecutor) {
+            FloatingContentCoordinator floatingContentCoordinator) {
         mContext = context;
         mPipTaskOrganizer = pipTaskOrganizer;
         mPipBoundsState = pipBoundsState;
@@ -179,15 +179,6 @@
         mSnapAlgorithm = snapAlgorithm;
         mFloatingContentCoordinator = floatingContentCoordinator;
         pipTransitionController.registerPipTransitionCallback(mPipTransitionCallback);
-        mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
-                mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
-
-        // Need to get the shell main thread sf vsync animation handler
-        mainExecutor.execute(() -> {
-            mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
-                    mSfAnimationHandlerThreadLocal.get());
-        });
-
         mResizePipUpdateListener = (target, values) -> {
             if (mPipBoundsState.getMotionBoundsState().isInMotion()) {
                 mPipTaskOrganizer.scheduleUserResizePip(getBounds(),
@@ -196,6 +187,14 @@
         };
     }
 
+    public void init() {
+        // Note: Needs to get the shell main thread sf vsync animation handler
+        mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
+                mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
+        mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
+                mSfAnimationHandlerThreadLocal.get());
+    }
+
     @NonNull
     @Override
     public Rect getFloatingBoundsOnScreen() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 78ee186..31057f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -132,8 +132,10 @@
         mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
         mPhonePipMenuController = menuActivityController;
         mPipUiEventLogger = pipUiEventLogger;
+    }
 
-        context.getDisplay().getRealSize(mMaxSize);
+    public void init() {
+        mContext.getDisplay().getRealSize(mMaxSize);
         reloadResources();
 
         mEnablePinchResize = DeviceConfig.getBoolean(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 5e23281..543ecfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -71,12 +71,13 @@
     private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
 
     // Allow PIP to resize to a slightly bigger state upon touch
-    private final boolean mEnableResize;
+    private boolean mEnableResize;
     private final Context mContext;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final @NonNull PipBoundsState mPipBoundsState;
     private final PipUiEventLogger mPipUiEventLogger;
     private final PipDismissTargetHandler mPipDismissTargetHandler;
+    private final ShellExecutor mMainExecutor;
 
     private PipResizeGestureHandler mPipResizeGestureHandler;
     private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
@@ -166,16 +167,18 @@
             ShellExecutor mainExecutor) {
         // Initialize the Pip input consumer
         mContext = context;
+        mMainExecutor = mainExecutor;
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipBoundsState = pipBoundsState;
         mMenuController = menuController;
         mPipUiEventLogger = pipUiEventLogger;
+        mFloatingContentCoordinator = floatingContentCoordinator;
         mMenuController.addListener(new PipMenuListener());
         mGesture = new DefaultPipTouchGesture();
         mMotionHelper = new PipMotionHelper(mContext, pipBoundsState, pipTaskOrganizer,
                 mMenuController, mPipBoundsAlgorithm.getSnapAlgorithm(), pipTransitionController,
-                floatingContentCoordinator, mainExecutor);
+                floatingContentCoordinator);
         mPipResizeGestureHandler =
                 new PipResizeGestureHandler(context, pipBoundsAlgorithm, pipBoundsState,
                         mMotionHelper, pipTaskOrganizer, this::getMovementBounds,
@@ -199,22 +202,26 @@
                 },
                 menuController::hideMenu,
                 mainExecutor);
-
-        Resources res = context.getResources();
-        mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
-        reloadResources();
-
-        mFloatingContentCoordinator = floatingContentCoordinator;
         mConnection = new PipAccessibilityInteractionConnection(mContext, pipBoundsState,
                 mMotionHelper, pipTaskOrganizer, mPipBoundsAlgorithm.getSnapAlgorithm(),
                 this::onAccessibilityShowMenu, this::updateMovementBounds, mainExecutor);
+    }
+
+    public void init() {
+        Resources res = mContext.getResources();
+        mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
+        reloadResources();
+
+        mMotionHelper.init();
+        mPipResizeGestureHandler.init();
+        mPipDismissTargetHandler.init();
 
         mEnableStash = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_STASHING,
                 /* defaultValue = */ true);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                mainExecutor,
+                mMainExecutor,
                 properties -> {
                     if (properties.getKeyset().contains(PIP_STASHING)) {
                         mEnableStash = properties.getBoolean(
@@ -226,7 +233,7 @@
                 PIP_STASH_MINIMUM_VELOCITY_THRESHOLD,
                 DEFAULT_STASH_VELOCITY_THRESHOLD);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                mainExecutor,
+                mMainExecutor,
                 properties -> {
                     if (properties.getKeyset().contains(PIP_STASH_MINIMUM_VELOCITY_THRESHOLD)) {
                         mStashVelocityThreshold = properties.getFloat(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index 32f3648..c6d994e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -280,7 +280,7 @@
                 : stableBounds.right - taskBounds.left - mButtonSize;
         final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize;
 
-        mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
+        updateSurfacePosition(leash, positionX, positionY);
     }
 
     void updateHintSurfacePosition() {
@@ -303,7 +303,16 @@
         final int positionY =
                 stableBounds.bottom - taskBounds.top - mPopupOffsetY - mHint.getMeasuredHeight();
 
-        mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
+        updateSurfacePosition(leash, positionX, positionY);
+    }
+
+    private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) {
+        mSyncQueue.runInSync(t -> {
+            t.setPosition(leash, positionX, positionY);
+            // The size compat UI should be the topmost child of the Task in case there can be more
+            // than one children.
+            t.setLayer(leash, Integer.MAX_VALUE);
+        });
     }
 
     int getDisplayId() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index c7fe5e7..b180bb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -362,8 +362,9 @@
 
     @Override
     public void onSnappedToDismiss(boolean bottomOrRight) {
-        final boolean mainStageToTop = bottomOrRight
-                && mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
+        final boolean mainStageToTop =
+                bottomOrRight ? mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT
+                        : mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT;
         exitSplitScreen(mainStageToTop ? mMainStage : mSideStage);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
new file mode 100644
index 0000000..2c4ceff
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.wm.shell.startingsurface;
+
+import android.os.IBinder;
+import android.window.StartingWindowInfo;
+
+/**
+ * Interface to engage starting window feature.
+ */
+public interface StartingSurface {
+    /**
+     * Called when a task need a starting window.
+     */
+    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
+    /**
+     * Called when the content of a task is ready to show, starting window can be removed.
+     */
+    void removeStartingWindow(int taskId);
+    /**
+     * Called when the Task wants to copy the splash screen.
+     * @param taskId
+     */
+    void copySplashScreenView(int taskId);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 5332291..8144071 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,15 +16,9 @@
 
 package com.android.wm.shell.startingsurface;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.res.Configuration.EMPTY;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
@@ -37,7 +31,6 @@
 import android.content.res.TypedArray;
 import android.hardware.display.DisplayManager;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -46,7 +39,6 @@
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
 import android.window.StartingWindowInfo;
-import android.window.TaskOrganizer;
 import android.window.TaskSnapshot;
 
 import com.android.internal.R;
@@ -56,19 +48,13 @@
 import java.util.function.Consumer;
 
 /**
- * Implementation to draw the starting window to an application, and remove the starting window
- * until the application displays its own window.
- *
- * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
- * starting window and attached to the Task, then when the Task want to remove the starting window,
- * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
- * class to remove the starting window of the Task.
+ * A class which able to draw splash screen or snapshot as the starting window for a task.
  * @hide
  */
 public class StartingSurfaceDrawer {
     static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
-    static final boolean DEBUG_SPLASH_SCREEN = false;
-    static final boolean DEBUG_TASK_SNAPSHOT = false;
+    static final boolean DEBUG_SPLASH_SCREEN = StartingWindowController.DEBUG_SPLASH_SCREEN;
+    static final boolean DEBUG_TASK_SNAPSHOT = StartingWindowController.DEBUG_TASK_SNAPSHOT;
 
     private final Context mContext;
     private final DisplayManager mDisplayManager;
@@ -107,106 +93,10 @@
         return context.createDisplayContext(targetDisplay);
     }
 
-    private static class PreferredStartingTypeHelper {
-        private static final int STARTING_TYPE_NO = 0;
-        private static final int STARTING_TYPE_SPLASH_SCREEN = 1;
-        private static final int STARTING_TYPE_SNAPSHOT = 2;
-
-        TaskSnapshot mSnapshot;
-        int mPreferredType;
-
-        PreferredStartingTypeHelper(StartingWindowInfo taskInfo) {
-            final int parameter = taskInfo.startingWindowTypeParameter;
-            final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
-            final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
-            final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
-            final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
-            final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
-            mPreferredType = preferredStartingWindowType(taskInfo, newTask, taskSwitch,
-                    processRunning, allowTaskSnapshot, activityCreated);
-        }
-
-        // reference from ActivityRecord#getStartingWindowType
-        private int preferredStartingWindowType(StartingWindowInfo windowInfo,
-                boolean newTask, boolean taskSwitch, boolean processRunning,
-                boolean allowTaskSnapshot, boolean activityCreated) {
-            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
-                Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
-                        + " taskSwitch " + taskSwitch
-                        + " processRunning " + processRunning
-                        + " allowTaskSnapshot " + allowTaskSnapshot
-                        + " activityCreated " + activityCreated);
-            }
-
-            if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
-                return STARTING_TYPE_SPLASH_SCREEN;
-            } else if (taskSwitch && allowTaskSnapshot) {
-                final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
-                if (isSnapshotCompatible(windowInfo, snapshot)) {
-                    return STARTING_TYPE_SNAPSHOT;
-                }
-                if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
-                    return STARTING_TYPE_SPLASH_SCREEN;
-                }
-                return STARTING_TYPE_NO;
-            } else {
-                return STARTING_TYPE_NO;
-            }
-        }
-
-        /**
-         * Returns {@code true} if the task snapshot is compatible with this activity (at least the
-         * rotation must be the same).
-         */
-        private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
-            if (snapshot == null) {
-                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
-                    Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
-                }
-                return false;
-            }
-
-            final int taskRotation = windowInfo.taskInfo.configuration
-                    .windowConfiguration.getRotation();
-            final int snapshotRotation = snapshot.getRotation();
-            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
-                Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
-                        + " snapshot " + snapshotRotation);
-            }
-            return taskRotation == snapshotRotation;
-        }
-
-        private TaskSnapshot getTaskSnapshot(int taskId) {
-            if (mSnapshot != null) {
-                return mSnapshot;
-            }
-            try {
-                mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
-                        false/* isLowResolution */);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
-                return null;
-            }
-            return mSnapshot;
-        }
-    }
-
     /**
-     * Called when a task need a starting window.
+     * Called when a task need a splash screen starting window.
      */
-    public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-        final PreferredStartingTypeHelper helper =
-                new PreferredStartingTypeHelper(windowInfo);
-        if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
-            addSplashScreenStartingWindow(windowInfo, appToken);
-        } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) {
-            final TaskSnapshot snapshot = helper.mSnapshot;
-            makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
-        }
-        // If prefer don't show, then don't show!
-    }
-
-    private void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+    public void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
         final RunningTaskInfo taskInfo = windowInfo.taskInfo;
         final ActivityInfo activityInfo = taskInfo.topActivityInfo;
         if (activityInfo == null) {
@@ -378,8 +268,8 @@
     /**
      * Called when a task need a snapshot starting window.
      */
-    private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
-            IBinder appToken, TaskSnapshot snapshot) {
+    void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo, IBinder appToken,
+            TaskSnapshot snapshot) {
         final int taskId = startingWindowInfo.taskInfo.taskId;
         final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
                 snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
new file mode 100644
index 0000000..73bf8ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 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.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.window.StartingWindowInfo;
+import android.window.TaskOrganizer;
+import android.window.TaskSnapshot;
+
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * Implementation to draw the starting window to an application, and remove the starting window
+ * until the application displays its own window.
+ *
+ * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
+ * starting window and attached to the Task, then when the Task want to remove the starting window,
+ * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
+ * class to remove the starting window of the Task.
+ * @hide
+ */
+public class StartingWindowController {
+    private static final String TAG = StartingWindowController.class.getSimpleName();
+    static final boolean DEBUG_SPLASH_SCREEN = false;
+    static final boolean DEBUG_TASK_SNAPSHOT = false;
+
+    private final StartingSurfaceDrawer mStartingSurfaceDrawer;
+    private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker();
+    private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
+
+    public StartingWindowController(Context context, ShellExecutor mainExecutor) {
+        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
+    }
+
+    /**
+     * Provide the implementation for Shell Module.
+     */
+    public StartingSurface asStartingSurface() {
+        return mImpl;
+    }
+
+    private static class StartingTypeChecker {
+        TaskSnapshot mSnapshot;
+
+        StartingTypeChecker() { }
+
+        private void reset() {
+            mSnapshot = null;
+        }
+
+        private @StartingWindowInfo.StartingWindowType int
+                estimateStartingWindowType(StartingWindowInfo windowInfo) {
+            reset();
+            final int parameter = windowInfo.startingWindowTypeParameter;
+            final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+            final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+            final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+            final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+            final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+            return estimateStartingWindowType(windowInfo, newTask, taskSwitch,
+                    processRunning, allowTaskSnapshot, activityCreated);
+        }
+
+        // reference from ActivityRecord#getStartingWindowType
+        private int estimateStartingWindowType(StartingWindowInfo windowInfo,
+                boolean newTask, boolean taskSwitch, boolean processRunning,
+                boolean allowTaskSnapshot, boolean activityCreated) {
+            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+                        + " taskSwitch " + taskSwitch
+                        + " processRunning " + processRunning
+                        + " allowTaskSnapshot " + allowTaskSnapshot
+                        + " activityCreated " + activityCreated);
+            }
+            if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+                return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+            }
+            if (taskSwitch && allowTaskSnapshot) {
+                final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
+                if (isSnapshotCompatible(windowInfo, snapshot)) {
+                    return STARTING_WINDOW_TYPE_SNAPSHOT;
+                }
+                if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+                    return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+                }
+            }
+            return STARTING_WINDOW_TYPE_NONE;
+        }
+
+        /**
+         * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+         * rotation must be the same).
+         */
+        private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
+            if (snapshot == null) {
+                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                    Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+                }
+                return false;
+            }
+
+            final int taskRotation = windowInfo.taskInfo.configuration
+                    .windowConfiguration.getRotation();
+            final int snapshotRotation = snapshot.getRotation();
+            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+                        + " snapshot " + snapshotRotation);
+            }
+            return taskRotation == snapshotRotation;
+        }
+
+        private TaskSnapshot getTaskSnapshot(int taskId) {
+            if (mSnapshot != null) {
+                return mSnapshot;
+            }
+            try {
+                mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
+                        false/* isLowResolution */);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
+                return null;
+            }
+            return mSnapshot;
+        }
+    }
+
+    /**
+     * Called when a task need a starting window.
+     */
+    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+        final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+        if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
+            mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
+        } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
+            final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
+            mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+        }
+        // If prefer don't show, then don't show!
+    }
+
+    void copySplashScreenView(int taskId) {
+        mStartingSurfaceDrawer.copySplashScreenView(taskId);
+    }
+
+    /**
+     * Called when the content of a task is ready to show, starting window can be removed.
+     */
+    void removeStartingWindow(int taskId) {
+        mStartingSurfaceDrawer.removeStartingWindow(taskId);
+    }
+
+    private class StartingSurfaceImpl implements StartingSurface {
+
+        @Override
+        public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+            StartingWindowController.this.addStartingWindow(windowInfo, appToken);
+        }
+
+        @Override
+        public void removeStartingWindow(int taskId) {
+            StartingWindowController.this.removeStartingWindow(taskId);
+        }
+
+        @Override
+        public void copySplashScreenView(int taskId) {
+            StartingWindowController.this.copySplashScreenView(taskId);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index a0e9f43..06b492d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -53,7 +53,6 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -79,8 +78,6 @@
     private Context mContext;
     @Mock
     private SizeCompatUIController mSizeCompatUI;
-    @Mock
-    private StartingSurfaceDrawer mStartingSurfaceDrawer;
 
     ShellTaskOrganizer mOrganizer;
     private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
@@ -116,7 +113,7 @@
                     .when(mTaskOrganizerController).registerTaskOrganizer(any());
         } catch (RemoteException e) {}
         mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
-                mSizeCompatUI, mStartingSurfaceDrawer));
+                mSizeCompatUI));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index d10c036..79ec624 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -43,7 +43,6 @@
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 
@@ -125,7 +124,7 @@
 
     @Test
     public void startSwipePipToHome_updatesOverrideMinSize() {
-        final Size minSize = new Size(100, 80);
+        final Size minSize = new Size(400, 320);
 
         mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize),
                 createPipParams(null));
@@ -153,7 +152,7 @@
 
     @Test
     public void onTaskAppeared_updatesOverrideMinSize() {
-        final Size minSize = new Size(100, 80);
+        final Size minSize = new Size(400, 320);
 
         mSpiedPipTaskOrganizer.onTaskAppeared(
                 createTaskInfo(mComponent1, createPipParams(null), minSize),
@@ -191,7 +190,7 @@
         mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
                 createPipParams(null)), null /* leash */);
 
-        final Size minSize = new Size(100, 80);
+        final Size minSize = new Size(400, 320);
         mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2,
                 createPipParams(null), minSize));
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 19930485..75ea4ac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -106,6 +106,7 @@
                 mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
                 mMockPipTransitionController, mFloatingContentCoordinator, mPipUiEventLogger,
                 mMainExecutor);
+        mPipTouchHandler.init();
         mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
         mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
         mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index de7d6c7..b9af9ce 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -125,7 +125,7 @@
         final Handler mainLoop = new Handler(Looper.getMainLooper());
         final StartingWindowInfo windowInfo =
                 createWindowInfo(taskId, android.R.style.Theme);
-        mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
+        mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
         verify(mStartingSurfaceDrawer).postAddWindow(
                 eq(taskId), eq(mBinder), any(), any(), any(), any());
@@ -143,7 +143,7 @@
         final Handler mainLoop = new Handler(Looper.getMainLooper());
         final StartingWindowInfo windowInfo =
                 createWindowInfo(taskId, 0);
-        mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
+        mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
         verify(mStartingSurfaceDrawer).postAddWindow(
                 eq(taskId), eq(mBinder), any(), any(), any(), any());
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 9c743ce..76366fc 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -156,7 +156,11 @@
                                                   std::move(loaded_idmap)));
 }
 
-const std::string& ApkAssets::GetPath() const {
+std::optional<std::string_view> ApkAssets::GetPath() const {
+  return assets_provider_->GetPath();
+}
+
+const std::string& ApkAssets::GetDebugName() const {
   return assets_provider_->GetDebugName();
 }
 
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 36bde5c..c0ef7be 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -116,8 +116,10 @@
   package_groups_.clear();
   package_ids_.fill(0xff);
 
-  // A mapping from apk assets path to the runtime package id of its first loaded package.
-  std::unordered_map<std::string, uint8_t> apk_assets_package_ids;
+  // A mapping from path of apk assets that could be target packages of overlays to the runtime
+  // package id of its first loaded package. Overlays currently can only override resources in the
+  // first package in the target resource table.
+  std::unordered_map<std::string, uint8_t> target_assets_package_ids;
 
   // Overlay resources are not directly referenced by an application so their resource ids
   // can change throughout the application's lifetime. Assign overlay package ids last.
@@ -140,8 +142,8 @@
     if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) {
       // The target package must precede the overlay package in the apk assets paths in order
       // to take effect.
-      auto iter = apk_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
-      if (iter == apk_assets_package_ids.end()) {
+      auto iter = target_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
+      if (iter == target_assets_package_ids.end()) {
          LOG(INFO) << "failed to find target package for overlay "
                    << loaded_idmap->OverlayApkPath();
       } else {
@@ -205,7 +207,10 @@
             package_name, static_cast<uint8_t>(entry.package_id));
       }
 
-      apk_assets_package_ids.insert(std::make_pair(apk_assets->GetPath(), package_id));
+      if (auto apk_assets_path = apk_assets->GetPath()) {
+        // Overlay target ApkAssets must have been created using path based load apis.
+        target_assets_package_ids.insert(std::make_pair(std::string(*apk_assets_path), package_id));
+      }
     }
   }
 
@@ -227,7 +232,7 @@
 
   std::string list;
   for (const auto& apk_assets : apk_assets_) {
-    base::StringAppendF(&list, "%s,", apk_assets->GetPath().c_str());
+    base::StringAppendF(&list, "%s,", apk_assets->GetDebugName().c_str());
   }
   LOG(INFO) << "ApkAssets: " << list;
 
@@ -383,8 +388,8 @@
   }
 }
 
-std::set<std::string> AssetManager2::GetNonSystemOverlayPaths() const {
-  std::set<std::string> non_system_overlays;
+std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const {
+  std::set<const ApkAssets*> non_system_overlays;
   for (const PackageGroup& package_group : package_groups_) {
     bool found_system_package = false;
     for (const ConfiguredPackage& package : package_group.packages_) {
@@ -396,7 +401,7 @@
 
     if (!found_system_package) {
       for (const ConfiguredOverlay& overlay : package_group.overlays_) {
-        non_system_overlays.insert(apk_assets_[overlay.cookie]->GetPath());
+        non_system_overlays.insert(apk_assets_[overlay.cookie]);
       }
     }
   }
@@ -408,7 +413,7 @@
     bool exclude_system, bool exclude_mipmap) const {
   ATRACE_NAME("AssetManager::GetResourceConfigurations");
   const auto non_system_overlays =
-      (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
+      (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
 
   std::set<ResTable_config> configurations;
   for (const PackageGroup& package_group : package_groups_) {
@@ -419,8 +424,8 @@
       }
 
       auto apk_assets = apk_assets_[package_group.cookies_[i]];
-      if (exclude_system && apk_assets->IsOverlay()
-          && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) {
+      if (exclude_system && apk_assets->IsOverlay() &&
+          non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
         // Exclude overlays that target system resources.
         continue;
       }
@@ -439,7 +444,7 @@
   ATRACE_NAME("AssetManager::GetResourceLocales");
   std::set<std::string> locales;
   const auto non_system_overlays =
-      (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
+      (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
 
   for (const PackageGroup& package_group : package_groups_) {
     for (size_t i = 0; i < package_group.packages_.size(); i++) {
@@ -449,8 +454,8 @@
       }
 
       auto apk_assets = apk_assets_[package_group.cookies_[i]];
-      if (exclude_system && apk_assets->IsOverlay()
-          && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) {
+      if (exclude_system && apk_assets->IsOverlay() &&
+          non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
         // Exclude overlays that target system resources.
         continue;
       }
@@ -491,7 +496,7 @@
       AssetDir::FileInfo info;
       info.setFileName(String8(name.data(), name.size()));
       info.setFileType(type);
-      info.setSourceName(String8(apk_assets->GetPath().c_str()));
+      info.setSourceName(String8(apk_assets->GetDebugName().c_str()));
       files->add(info);
     };
 
@@ -846,7 +851,7 @@
     }
 
     log_stream << "\n\t" << prefix->second << ": " << *step.package_name << " ("
-               << apk_assets_[step.cookie]->GetPath() << ")";
+               << apk_assets_[step.cookie]->GetDebugName() << ")";
     if (!step.config_name.isEmpty()) {
       log_stream << " -" << step.config_name;
     }
@@ -1556,41 +1561,32 @@
     std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
 
     // Determine which ApkAssets are loaded in both theme AssetManagers.
-    std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
+    const auto src_assets = o.asset_manager_->GetApkAssets();
     for (size_t i = 0; i < src_assets.size(); i++) {
       const ApkAssets* src_asset = src_assets[i];
 
-      std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets();
+      const auto dest_assets = asset_manager_->GetApkAssets();
       for (size_t j = 0; j < dest_assets.size(); j++) {
         const ApkAssets* dest_asset = dest_assets[j];
-
-        // Map the runtime package of the source apk asset to the destination apk asset.
-        if (src_asset->GetPath() == dest_asset->GetPath()) {
-          const auto& src_packages = src_asset->GetLoadedArsc()->GetPackages();
-          const auto& dest_packages = dest_asset->GetLoadedArsc()->GetPackages();
-
-          SourceToDestinationRuntimePackageMap package_map;
-
-          // The source and destination package should have the same number of packages loaded in
-          // the same order.
-          const size_t N = src_packages.size();
-          CHECK(N == dest_packages.size())
-              << " LoadedArsc " << src_asset->GetPath() << " differs number of packages.";
-          for (size_t p = 0; p < N; p++) {
-            auto& src_package = src_packages[p];
-            auto& dest_package = dest_packages[p];
-            CHECK(src_package->GetPackageName() == dest_package->GetPackageName())
-                << " Package " << src_package->GetPackageName() << " differs in load order.";
-
-            int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get());
-            int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get());
-            package_map[src_package_id] = dest_package_id;
-          }
-
-          src_to_dest_asset_cookies.insert(std::make_pair(i, j));
-          src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
-          break;
+        if (src_asset != dest_asset) {
+          // ResourcesManager caches and reuses ApkAssets when the same apk must be present in
+          // multiple AssetManagers. Two ApkAssets point to the same version of the same resources
+          // if they are the same instance.
+          continue;
         }
+
+        // Map the package ids of the asset in the source AssetManager to the package ids of the
+        // asset in th destination AssetManager.
+        SourceToDestinationRuntimePackageMap package_map;
+        for (const auto& loaded_package : src_asset->GetLoadedArsc()->GetPackages()) {
+          const int src_package_id = o.asset_manager_->GetAssignedPackageId(loaded_package.get());
+          const int dest_package_id = asset_manager_->GetAssignedPackageId(loaded_package.get());
+          package_map[src_package_id] = dest_package_id;
+        }
+
+        src_to_dest_asset_cookies.insert(std::make_pair(i, j));
+        src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
+        break;
       }
     }
 
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index f3c48f7..0aaf0b3 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -261,6 +261,13 @@
   return entry.crc32;
 }
 
+std::optional<std::string_view> ZipAssetsProvider::GetPath() const {
+  if (name_.GetPath() != nullptr) {
+    return *name_.GetPath();
+  }
+  return {};
+}
+
 const std::string& ZipAssetsProvider::GetDebugName() const {
   return name_.GetDebugName();
 }
@@ -318,6 +325,10 @@
   return true;
 }
 
+std::optional<std::string_view> DirectoryAssetsProvider::GetPath() const {
+  return dir_;
+}
+
 const std::string& DirectoryAssetsProvider::GetDebugName() const {
   return dir_;
 }
@@ -336,13 +347,9 @@
                                          std::unique_ptr<AssetsProvider>&& secondary)
                       : primary_(std::forward<std::unique_ptr<AssetsProvider>>(primary)),
                         secondary_(std::forward<std::unique_ptr<AssetsProvider>>(secondary)) {
-  if (primary_->GetDebugName() == kEmptyDebugString) {
-    debug_name_ = secondary_->GetDebugName();
-  } else if (secondary_->GetDebugName() == kEmptyDebugString) {
-    debug_name_ = primary_->GetDebugName();
-  } else {
-    debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName();
-  }
+  debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName();
+  path_ = (primary_->GetDebugName() != kEmptyDebugString) ? primary_->GetPath()
+                                                          : secondary_->GetPath();
 }
 
 std::unique_ptr<AssetsProvider> MultiAssetsProvider::Create(
@@ -367,6 +374,10 @@
   return primary_->ForEachFile(root_path, f) && secondary_->ForEachFile(root_path, f);
 }
 
+std::optional<std::string_view> MultiAssetsProvider::GetPath() const {
+  return path_;
+}
+
 const std::string& MultiAssetsProvider::GetDebugName() const {
   return debug_name_;
 }
@@ -394,6 +405,10 @@
   return true;
 }
 
+std::optional<std::string_view> EmptyAssetsProvider::GetPath() const {
+  return {};
+}
+
 const std::string& EmptyAssetsProvider::GetDebugName() const {
   const static std::string kEmpty = kEmptyDebugString;
   return kEmpty;
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index d0019ed..6f88f41 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -34,7 +34,6 @@
 // Holds an APK.
 class ApkAssets {
  public:
-
   // Creates an ApkAssets from a path on device.
   static std::unique_ptr<ApkAssets> Load(const std::string& path,
                                          package_property_t flags = 0U);
@@ -61,12 +60,11 @@
   static std::unique_ptr<ApkAssets> LoadOverlay(const std::string& idmap_path,
                                                 package_property_t flags = 0U);
 
-  // TODO(177101983): Remove all uses of GetPath for checking whether two ApkAssets are the same.
-  //  With the introduction of ResourcesProviders, not all ApkAssets have paths. This could cause
-  //  bugs when path is used for comparison because multiple ApkAssets could have the same "firendly
-  //  name". Use pointer equality instead. ResourceManager caches and reuses ApkAssets so the
-  //  same asset should have the same pointer.
-  const std::string& GetPath() const;
+  // Path to the contents of the ApkAssets on disk. The path could represent an APk, a directory,
+  // or some other file type.
+  std::optional<std::string_view> GetPath() const;
+
+  const std::string& GetDebugName() const;
 
   const AssetsProvider* GetAssetsProvider() const {
     return assets_provider_.get();
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 2255973f..119f531 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -412,7 +412,7 @@
   void RebuildFilterList();
 
   // Retrieves the APK paths of overlays that overlay non-system packages.
-  std::set<std::string> GetNonSystemOverlayPaths() const;
+  std::set<const ApkAssets*> GetNonSystemOverlays() const;
 
   // AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
   // been seen while traversing bag parents.
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index 6f16ff4..63bbdcc 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -48,6 +48,10 @@
   virtual bool ForEachFile(const std::string& path,
                            const std::function<void(const StringPiece&, FileType)>& f) const = 0;
 
+  // Retrieves the path to the contents of the AssetsProvider on disk. The path could represent an
+  // APk, a directory, or some other file type.
+  WARN_UNUSED virtual std::optional<std::string_view> GetPath() const = 0;
+
   // Retrieves a name that represents the interface. This may or may not be the path of the
   // interface source.
   WARN_UNUSED virtual const std::string& GetDebugName() const = 0;
@@ -85,9 +89,9 @@
   bool ForEachFile(const std::string& root_path,
                    const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
-
   WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
 
   ~ZipAssetsProvider() override = default;
@@ -125,6 +129,7 @@
   bool ForEachFile(const std::string& path,
                    const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
@@ -149,6 +154,7 @@
   bool ForEachFile(const std::string& root_path,
                    const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
@@ -163,6 +169,7 @@
 
   std::unique_ptr<AssetsProvider> primary_;
   std::unique_ptr<AssetsProvider> secondary_;
+  std::optional<std::string_view> path_;
   std::string debug_name_;
 };
 
@@ -173,6 +180,7 @@
   bool ForEachFile(const std::string& path,
                   const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 77ceda9..d663c52 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -421,7 +421,6 @@
                 "libstatspull",
                 "libstatssocket",
                 "libpdfium",
-                "libbinder_ndk",
             ],
             static_libs: [
                 "libgif",
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 912d04c5..e9b2f4a 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -80,6 +80,10 @@
     explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
         memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
         set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
+        // The struct is zeroed by memset above. That also sets FrameInfoIndex::InputEventId to
+        // equal android::os::IInputConstants::INVALID_INPUT_EVENT_ID == 0.
+        // Therefore, we can skip setting the value for InputEventId here. If the value for
+        // INVALID_INPUT_EVENT_ID changes, this code would have to be updated, as well.
         set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max();
     }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 609706e..5540e2d 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -552,8 +552,8 @@
 
     bool promotedToLayer() const {
         return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
-               (mComputedFields.mNeedLayerForFunctors ||
-                mLayerProperties.mImageFilter != nullptr ||
+               (mComputedFields.mNeedLayerForFunctors || mLayerProperties.mImageFilter != nullptr ||
+                !mLayerProperties.getStretchEffect().isEmpty() ||
                 (!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
                  mPrimitiveFields.mHasOverlappingRendering));
     }
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index 51cbc75..d4fd105 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -15,13 +15,195 @@
  */
 
 #include "StretchEffect.h"
+#include <SkImageFilter.h>
+#include <SkRefCnt.h>
+#include <SkRuntimeEffect.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <include/effects/SkImageFilters.h>
+
+#include <memory>
 
 namespace android::uirenderer {
 
-sk_sp<SkImageFilter> StretchEffect::getImageFilter() const {
-    // TODO: Implement & Cache
-    // Probably need to use mutable to achieve caching
-    return nullptr;
+static const SkString stretchShader = SkString(R"(
+    uniform shader uContentTexture;
+
+    // multiplier to apply to scale effect
+    uniform float uMaxStretchIntensity;
+
+    // Maximum percentage to stretch beyond bounds  of target
+    uniform float uStretchAffectedDist;
+
+    // Distance stretched as a function of the normalized overscroll times
+    // scale intensity
+    uniform float uDistanceStretchedX;
+    uniform float uDistanceStretchedY;
+    uniform float uDistDiffX;
+
+    // Difference between the peak stretch amount and overscroll amount normalized
+    uniform float uDistDiffY;
+
+    // Horizontal offset represented as a ratio of pixels divided by the target width
+    uniform float uScrollX;
+    // Vertical offset represented as a ratio of pixels divided by the target height
+    uniform float uScrollY;
+
+    // Normalized overscroll amount in the horizontal direction
+    uniform float uOverscrollX;
+
+    // Normalized overscroll amount in the vertical direction
+    uniform float uOverscrollY;
+    uniform float viewportWidth; // target height in pixels
+    uniform float viewportHeight; // target width in pixels
+
+    void computeOverscrollStart(
+        out float outPos,
+        float inPos,
+        float overscroll,
+        float uStretchAffectedDist,
+        float distanceStretched
+    ) {
+        float offsetPos = uStretchAffectedDist - inPos;
+        float posBasedVariation = smoothstep(0., uStretchAffectedDist, offsetPos);
+        float stretchIntensity = overscroll * posBasedVariation;
+        outPos = distanceStretched - (offsetPos / (1. + stretchIntensity));
+    }
+
+    void computeOverscrollEnd(
+        out float outPos,
+        float inPos,
+        float overscroll,
+        float reverseStretchDist,
+        float uStretchAffectedDist,
+        float distanceStretched
+    ) {
+        float offsetPos = inPos - reverseStretchDist;
+        float posBasedVariation = (smoothstep(0., uStretchAffectedDist, offsetPos));
+        float stretchIntensity = (-overscroll) * posBasedVariation;
+        outPos = 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
+    }
+
+    void computeOverscroll(
+        out float outPos,
+        float inPos,
+        float overscroll,
+        float uStretchAffectedDist,
+        float distanceStretched,
+        float distanceDiff
+    ) {
+        if (overscroll > 0) {
+            if (inPos <= uStretchAffectedDist) {
+                computeOverscrollStart(
+                  outPos,
+                  inPos,
+                  overscroll,
+                  uStretchAffectedDist,
+                  distanceStretched
+                );
+            } else if (inPos >= distanceStretched) {
+                outPos = distanceDiff + inPos;
+            }
+        }
+        if (overscroll < 0) {
+            float stretchAffectedDist = 1. - uStretchAffectedDist;
+            if (inPos >= stretchAffectedDist) {
+                computeOverscrollEnd(
+                  outPos,
+                  inPos,
+                  overscroll,
+                  stretchAffectedDist,
+                  uStretchAffectedDist,
+                  distanceStretched
+                );
+            } else if (inPos < stretchAffectedDist) {
+                outPos = -distanceDiff + inPos;
+            }
+        }
+    }
+
+    vec4 main(vec2 coord) {
+        // Normalize SKSL pixel coordinate into a unit vector
+        float inU = coord.x / viewportWidth;
+        float inV = coord.y / viewportHeight;
+        float outU;
+        float outV;
+        float stretchIntensity;
+        // Add the normalized scroll position within scrolling list
+        inU += uScrollX;
+        inV += uScrollY;
+        outU = inU;
+        outV = inV;
+        computeOverscroll(
+            outU,
+            inU,
+            uOverscrollX,
+            uStretchAffectedDist,
+            uDistanceStretchedX,
+            uDistDiffX
+        );
+        computeOverscroll(
+            outV,
+            inV,
+            uOverscrollY,
+            uStretchAffectedDist,
+            uDistanceStretchedY,
+            uDistDiffY
+        );
+        coord.x = outU * viewportWidth;
+        coord.y = outV * viewportHeight;
+        return sample(uContentTexture, coord);
+    })");
+
+static const float ZERO = 0.f;
+
+sk_sp<SkImageFilter> StretchEffect::getImageFilter(const sk_sp<SkImage>& snapshotImage) const {
+    if (isEmpty()) {
+        return nullptr;
+    }
+
+    if (mStretchFilter != nullptr) {
+        return mStretchFilter;
+    }
+
+    float distanceNotStretchedX = maxStretchAmount / stretchArea.width();
+    float distanceNotStretchedY = maxStretchAmount / stretchArea.height();
+    float normOverScrollDistX = mStretchDirection.x();
+    float normOverScrollDistY = mStretchDirection.y();
+    float distanceStretchedX = maxStretchAmount / (1 + abs(normOverScrollDistX));
+    float distanceStretchedY = maxStretchAmount / (1 + abs(normOverScrollDistY));
+    float diffX = distanceStretchedX - distanceNotStretchedX;
+    float diffY = distanceStretchedY - distanceNotStretchedY;
+    float viewportWidth = stretchArea.width();
+    float viewportHeight = stretchArea.height();
+
+    if (mBuilder == nullptr) {
+        mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
+    }
+
+    mBuilder->child("uContentTexture") = snapshotImage->makeShader(
+            SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
+    mBuilder->uniform("uStretchAffectedDist").set(&maxStretchAmount, 1);
+    mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1);
+    mBuilder->uniform("uDistanceStretchedY").set(&distanceStretchedY, 1);
+    mBuilder->uniform("uDistDiffX").set(&diffX, 1);
+    mBuilder->uniform("uDistDiffY").set(&diffY, 1);
+    mBuilder->uniform("uOverscrollX").set(&normOverScrollDistX, 1);
+    mBuilder->uniform("uOverscrollY").set(&normOverScrollDistY, 1);
+    mBuilder->uniform("uScrollX").set(&ZERO, 1);
+    mBuilder->uniform("uScrollY").set(&ZERO, 1);
+    mBuilder->uniform("viewportWidth").set(&viewportWidth, 1);
+    mBuilder->uniform("viewportHeight").set(&viewportHeight, 1);
+
+    mStretchFilter = SkImageFilters::Shader(mBuilder->makeShader(nullptr, false),
+                                            SkRect{0, 0, viewportWidth, viewportHeight});
+
+    return mStretchFilter;
+}
+
+sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
+    const static SkRuntimeEffect::Result instance = SkRuntimeEffect::Make(stretchShader);
+    return instance.effect;
 }
 
 } // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index 7dfd639..d2da06b 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -18,9 +18,11 @@
 
 #include "utils/MathUtils.h"
 
+#include <SkImage.h>
+#include <SkImageFilter.h>
 #include <SkPoint.h>
 #include <SkRect.h>
-#include <SkImageFilter.h>
+#include <SkRuntimeEffect.h>
 
 namespace android::uirenderer {
 
@@ -31,15 +33,27 @@
         SmoothStep,
     };
 
+    StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmount)
+            : stretchArea(area), maxStretchAmount(maxStretchAmount), mStretchDirection(direction) {}
+
+    StretchEffect() {}
+
     bool isEmpty() const {
-        return MathUtils::isZero(stretchDirection.x())
-                && MathUtils::isZero(stretchDirection.y());
+        return MathUtils::isZero(mStretchDirection.x()) && MathUtils::isZero(mStretchDirection.y());
     }
 
     void setEmpty() {
         *this = StretchEffect{};
     }
 
+    StretchEffect& operator=(const StretchEffect& other) {
+        this->stretchArea = other.stretchArea;
+        this->mStretchDirection = other.mStretchDirection;
+        this->mStretchFilter = nullptr;
+        this->maxStretchAmount = other.maxStretchAmount;
+        return *this;
+    }
+
     void mergeWith(const StretchEffect& other) {
         if (other.isEmpty()) {
             return;
@@ -48,7 +62,7 @@
             *this = other;
             return;
         }
-        stretchDirection += other.stretchDirection;
+        setStretchDirection(mStretchDirection + other.mStretchDirection);
         if (isEmpty()) {
             return setEmpty();
         }
@@ -56,11 +70,23 @@
         maxStretchAmount = std::max(maxStretchAmount, other.maxStretchAmount);
     }
 
-    sk_sp<SkImageFilter> getImageFilter() const;
+    sk_sp<SkImageFilter> getImageFilter(const sk_sp<SkImage>& snapshotImage) const;
 
     SkRect stretchArea {0, 0, 0, 0};
-    SkVector stretchDirection {0, 0};
     float maxStretchAmount = 0;
+
+    void setStretchDirection(const SkVector& direction) {
+        mStretchFilter = nullptr;
+        mStretchDirection = direction;
+    }
+
+    const SkVector getStretchDirection() const { return mStretchDirection; }
+
+private:
+    static sk_sp<SkRuntimeEffect> getStretchEffect();
+    mutable SkVector mStretchDirection{0, 0};
+    mutable std::unique_ptr<SkRuntimeShaderBuilder> mBuilder;
+    mutable sk_sp<SkImageFilter> mStretchFilter;
 };
 
 } // namespace android::uirenderer
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 5f60437..fc7d0d1 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -180,14 +180,13 @@
 }
 
 static jboolean android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
-        jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat vX, jfloat vY, jfloat max) {
+                                                jfloat left, jfloat top, jfloat right,
+                                                jfloat bottom, jfloat vX, jfloat vY, jfloat max) {
+    StretchEffect effect =
+            StretchEffect(SkRect::MakeLTRB(left, top, right, bottom), {.fX = vX, .fY = vY}, max);
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutateLayerProperties().mutableStretchEffect().mergeWith(
-            StretchEffect{
-        .stretchArea = SkRect::MakeLTRB(left, top, right, bottom),
-        .stretchDirection = {.fX = vX, .fY = vY},
-        .maxStretchAmount = max
-    });
+            effect);
     renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
     return true;
 }
@@ -659,10 +658,11 @@
                 return;
             }
 #ifdef __ANDROID__  // Layoutlib does not support CanvasContext
+            SkVector stretchDirection = effect->getStretchDirection();
             env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
                                 info.canvasContext.getFrameNumber(), area.left, area.top,
-                                area.right, area.bottom, effect->stretchDirection.fX,
-                                effect->stretchDirection.fY, effect->maxStretchAmount);
+                                area.right, area.bottom, stretchDirection.fX, stretchDirection.fY,
+                                effect->maxStretchAmount);
 #endif
             env->DeleteLocalRef(localref);
         }
@@ -702,106 +702,110 @@
 const char* const kClassPathName = "android/graphics/RenderNode";
 
 static const JNINativeMethod gMethods[] = {
-// ----------------------------------------------------------------------------
-// Regular JNI
-// ----------------------------------------------------------------------------
-    { "nCreate",               "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
-    { "nGetNativeFinalizer",   "()J",    (void*) android_view_RenderNode_getNativeFinalizer },
-    { "nOutput",               "(J)V",    (void*) android_view_RenderNode_output },
-    { "nGetUsageSize",         "(J)I",    (void*) android_view_RenderNode_getUsageSize },
-    { "nGetAllocatedSize",         "(J)I",    (void*) android_view_RenderNode_getAllocatedSize },
-    { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
-    { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
-    { "nRequestPositionUpdates",   "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },
+        // ----------------------------------------------------------------------------
+        // Regular JNI
+        // ----------------------------------------------------------------------------
+        {"nCreate", "(Ljava/lang/String;)J", (void*)android_view_RenderNode_create},
+        {"nGetNativeFinalizer", "()J", (void*)android_view_RenderNode_getNativeFinalizer},
+        {"nOutput", "(J)V", (void*)android_view_RenderNode_output},
+        {"nGetUsageSize", "(J)I", (void*)android_view_RenderNode_getUsageSize},
+        {"nGetAllocatedSize", "(J)I", (void*)android_view_RenderNode_getAllocatedSize},
+        {"nAddAnimator", "(JJ)V", (void*)android_view_RenderNode_addAnimator},
+        {"nEndAllAnimators", "(J)V", (void*)android_view_RenderNode_endAllAnimators},
+        {"nRequestPositionUpdates", "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V",
+         (void*)android_view_RenderNode_requestPositionUpdates},
 
-// ----------------------------------------------------------------------------
-// Critical JNI via @CriticalNative annotation in RenderNode.java
-// ----------------------------------------------------------------------------
-    { "nDiscardDisplayList",   "(J)V",   (void*) android_view_RenderNode_discardDisplayList },
-    { "nIsValid",              "(J)Z",   (void*) android_view_RenderNode_isValid },
-    { "nSetLayerType",         "(JI)Z",  (void*) android_view_RenderNode_setLayerType },
-    { "nGetLayerType",         "(J)I",   (void*) android_view_RenderNode_getLayerType },
-    { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
-    { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
-    { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
-    { "nGetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_getAnimationMatrix },
-    { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
-    { "nGetClipToBounds",      "(J)Z",   (void*) android_view_RenderNode_getClipToBounds },
-    { "nSetClipBounds",        "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
-    { "nSetClipBoundsEmpty",   "(J)Z",   (void*) android_view_RenderNode_setClipBoundsEmpty },
-    { "nSetProjectBackwards",  "(JZ)Z",  (void*) android_view_RenderNode_setProjectBackwards },
-    { "nSetProjectionReceiver","(JZ)Z",  (void*) android_view_RenderNode_setProjectionReceiver },
+        // ----------------------------------------------------------------------------
+        // Critical JNI via @CriticalNative annotation in RenderNode.java
+        // ----------------------------------------------------------------------------
+        {"nDiscardDisplayList", "(J)V", (void*)android_view_RenderNode_discardDisplayList},
+        {"nIsValid", "(J)Z", (void*)android_view_RenderNode_isValid},
+        {"nSetLayerType", "(JI)Z", (void*)android_view_RenderNode_setLayerType},
+        {"nGetLayerType", "(J)I", (void*)android_view_RenderNode_getLayerType},
+        {"nSetLayerPaint", "(JJ)Z", (void*)android_view_RenderNode_setLayerPaint},
+        {"nSetStaticMatrix", "(JJ)Z", (void*)android_view_RenderNode_setStaticMatrix},
+        {"nSetAnimationMatrix", "(JJ)Z", (void*)android_view_RenderNode_setAnimationMatrix},
+        {"nGetAnimationMatrix", "(JJ)Z", (void*)android_view_RenderNode_getAnimationMatrix},
+        {"nSetClipToBounds", "(JZ)Z", (void*)android_view_RenderNode_setClipToBounds},
+        {"nGetClipToBounds", "(J)Z", (void*)android_view_RenderNode_getClipToBounds},
+        {"nSetClipBounds", "(JIIII)Z", (void*)android_view_RenderNode_setClipBounds},
+        {"nSetClipBoundsEmpty", "(J)Z", (void*)android_view_RenderNode_setClipBoundsEmpty},
+        {"nSetProjectBackwards", "(JZ)Z", (void*)android_view_RenderNode_setProjectBackwards},
+        {"nSetProjectionReceiver", "(JZ)Z", (void*)android_view_RenderNode_setProjectionReceiver},
 
-    { "nSetOutlineRoundRect",  "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
-    { "nSetOutlinePath",       "(JJF)Z", (void*) android_view_RenderNode_setOutlinePath },
-    { "nSetOutlineEmpty",      "(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
-    { "nSetOutlineNone",       "(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
-    { "nClearStretch",         "(J)Z",   (void*) android_view_RenderNode_clearStretch },
-    { "nStretch",              "(JFFFFFFF)Z",   (void*) android_view_RenderNode_stretch },
-    { "nHasShadow",            "(J)Z",   (void*) android_view_RenderNode_hasShadow },
-    { "nSetSpotShadowColor",   "(JI)Z",  (void*) android_view_RenderNode_setSpotShadowColor },
-    { "nGetSpotShadowColor",   "(J)I",   (void*) android_view_RenderNode_getSpotShadowColor },
-    { "nSetAmbientShadowColor","(JI)Z",  (void*) android_view_RenderNode_setAmbientShadowColor },
-    { "nGetAmbientShadowColor","(J)I",   (void*) android_view_RenderNode_getAmbientShadowColor },
-    { "nSetClipToOutline",     "(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
-    { "nSetRevealClip",        "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
+        {"nSetOutlineRoundRect", "(JIIIIFF)Z", (void*)android_view_RenderNode_setOutlineRoundRect},
+        {"nSetOutlinePath", "(JJF)Z", (void*)android_view_RenderNode_setOutlinePath},
+        {"nSetOutlineEmpty", "(J)Z", (void*)android_view_RenderNode_setOutlineEmpty},
+        {"nSetOutlineNone", "(J)Z", (void*)android_view_RenderNode_setOutlineNone},
+        {"nClearStretch", "(J)Z", (void*)android_view_RenderNode_clearStretch},
+        {"nStretch", "(JFFFFFFF)Z", (void*)android_view_RenderNode_stretch},
+        {"nHasShadow", "(J)Z", (void*)android_view_RenderNode_hasShadow},
+        {"nSetSpotShadowColor", "(JI)Z", (void*)android_view_RenderNode_setSpotShadowColor},
+        {"nGetSpotShadowColor", "(J)I", (void*)android_view_RenderNode_getSpotShadowColor},
+        {"nSetAmbientShadowColor", "(JI)Z", (void*)android_view_RenderNode_setAmbientShadowColor},
+        {"nGetAmbientShadowColor", "(J)I", (void*)android_view_RenderNode_getAmbientShadowColor},
+        {"nSetClipToOutline", "(JZ)Z", (void*)android_view_RenderNode_setClipToOutline},
+        {"nSetRevealClip", "(JZFFF)Z", (void*)android_view_RenderNode_setRevealClip},
 
-    { "nSetAlpha",             "(JF)Z",  (void*) android_view_RenderNode_setAlpha },
-    { "nSetRenderEffect",      "(JJ)Z",  (void*) android_view_RenderNode_setRenderEffect },
-    { "nSetHasOverlappingRendering", "(JZ)Z",
-            (void*) android_view_RenderNode_setHasOverlappingRendering },
-    { "nSetUsageHint",    "(JI)V", (void*) android_view_RenderNode_setUsageHint },
-    { "nSetElevation",         "(JF)Z",  (void*) android_view_RenderNode_setElevation },
-    { "nSetTranslationX",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationX },
-    { "nSetTranslationY",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationY },
-    { "nSetTranslationZ",      "(JF)Z",  (void*) android_view_RenderNode_setTranslationZ },
-    { "nSetRotation",          "(JF)Z",  (void*) android_view_RenderNode_setRotation },
-    { "nSetRotationX",         "(JF)Z",  (void*) android_view_RenderNode_setRotationX },
-    { "nSetRotationY",         "(JF)Z",  (void*) android_view_RenderNode_setRotationY },
-    { "nSetScaleX",            "(JF)Z",  (void*) android_view_RenderNode_setScaleX },
-    { "nSetScaleY",            "(JF)Z",  (void*) android_view_RenderNode_setScaleY },
-    { "nSetPivotX",            "(JF)Z",  (void*) android_view_RenderNode_setPivotX },
-    { "nSetPivotY",            "(JF)Z",  (void*) android_view_RenderNode_setPivotY },
-    { "nResetPivot",           "(J)Z",   (void*) android_view_RenderNode_resetPivot },
-    { "nSetCameraDistance",    "(JF)Z",  (void*) android_view_RenderNode_setCameraDistance },
-    { "nSetLeft",              "(JI)Z",  (void*) android_view_RenderNode_setLeft },
-    { "nSetTop",               "(JI)Z",  (void*) android_view_RenderNode_setTop },
-    { "nSetRight",             "(JI)Z",  (void*) android_view_RenderNode_setRight },
-    { "nSetBottom",            "(JI)Z",  (void*) android_view_RenderNode_setBottom },
-    { "nGetLeft",              "(J)I",  (void*) android_view_RenderNode_getLeft },
-    { "nGetTop",               "(J)I",  (void*) android_view_RenderNode_getTop },
-    { "nGetRight",             "(J)I",  (void*) android_view_RenderNode_getRight },
-    { "nGetBottom",            "(J)I",  (void*) android_view_RenderNode_getBottom },
-    { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
-    { "nOffsetLeftAndRight",   "(JI)Z",  (void*) android_view_RenderNode_offsetLeftAndRight },
-    { "nOffsetTopAndBottom",   "(JI)Z",  (void*) android_view_RenderNode_offsetTopAndBottom },
+        {"nSetAlpha", "(JF)Z", (void*)android_view_RenderNode_setAlpha},
+        {"nSetRenderEffect", "(JJ)Z", (void*)android_view_RenderNode_setRenderEffect},
+        {"nSetHasOverlappingRendering", "(JZ)Z",
+         (void*)android_view_RenderNode_setHasOverlappingRendering},
+        {"nSetUsageHint", "(JI)V", (void*)android_view_RenderNode_setUsageHint},
+        {"nSetElevation", "(JF)Z", (void*)android_view_RenderNode_setElevation},
+        {"nSetTranslationX", "(JF)Z", (void*)android_view_RenderNode_setTranslationX},
+        {"nSetTranslationY", "(JF)Z", (void*)android_view_RenderNode_setTranslationY},
+        {"nSetTranslationZ", "(JF)Z", (void*)android_view_RenderNode_setTranslationZ},
+        {"nSetRotation", "(JF)Z", (void*)android_view_RenderNode_setRotation},
+        {"nSetRotationX", "(JF)Z", (void*)android_view_RenderNode_setRotationX},
+        {"nSetRotationY", "(JF)Z", (void*)android_view_RenderNode_setRotationY},
+        {"nSetScaleX", "(JF)Z", (void*)android_view_RenderNode_setScaleX},
+        {"nSetScaleY", "(JF)Z", (void*)android_view_RenderNode_setScaleY},
+        {"nSetPivotX", "(JF)Z", (void*)android_view_RenderNode_setPivotX},
+        {"nSetPivotY", "(JF)Z", (void*)android_view_RenderNode_setPivotY},
+        {"nResetPivot", "(J)Z", (void*)android_view_RenderNode_resetPivot},
+        {"nSetCameraDistance", "(JF)Z", (void*)android_view_RenderNode_setCameraDistance},
+        {"nSetLeft", "(JI)Z", (void*)android_view_RenderNode_setLeft},
+        {"nSetTop", "(JI)Z", (void*)android_view_RenderNode_setTop},
+        {"nSetRight", "(JI)Z", (void*)android_view_RenderNode_setRight},
+        {"nSetBottom", "(JI)Z", (void*)android_view_RenderNode_setBottom},
+        {"nGetLeft", "(J)I", (void*)android_view_RenderNode_getLeft},
+        {"nGetTop", "(J)I", (void*)android_view_RenderNode_getTop},
+        {"nGetRight", "(J)I", (void*)android_view_RenderNode_getRight},
+        {"nGetBottom", "(J)I", (void*)android_view_RenderNode_getBottom},
+        {"nSetLeftTopRightBottom", "(JIIII)Z",
+         (void*)android_view_RenderNode_setLeftTopRightBottom},
+        {"nOffsetLeftAndRight", "(JI)Z", (void*)android_view_RenderNode_offsetLeftAndRight},
+        {"nOffsetTopAndBottom", "(JI)Z", (void*)android_view_RenderNode_offsetTopAndBottom},
 
-    { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
-    { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
-    { "nGetAlpha",                "(J)F",  (void*) android_view_RenderNode_getAlpha },
-    { "nGetCameraDistance",       "(J)F",  (void*) android_view_RenderNode_getCameraDistance },
-    { "nGetScaleX",               "(J)F",  (void*) android_view_RenderNode_getScaleX },
-    { "nGetScaleY",               "(J)F",  (void*) android_view_RenderNode_getScaleY },
-    { "nGetElevation",            "(J)F",  (void*) android_view_RenderNode_getElevation },
-    { "nGetTranslationX",         "(J)F",  (void*) android_view_RenderNode_getTranslationX },
-    { "nGetTranslationY",         "(J)F",  (void*) android_view_RenderNode_getTranslationY },
-    { "nGetTranslationZ",         "(J)F",  (void*) android_view_RenderNode_getTranslationZ },
-    { "nGetRotation",             "(J)F",  (void*) android_view_RenderNode_getRotation },
-    { "nGetRotationX",            "(J)F",  (void*) android_view_RenderNode_getRotationX },
-    { "nGetRotationY",            "(J)F",  (void*) android_view_RenderNode_getRotationY },
-    { "nIsPivotExplicitlySet",    "(J)Z",  (void*) android_view_RenderNode_isPivotExplicitlySet },
-    { "nHasIdentityMatrix",       "(J)Z",  (void*) android_view_RenderNode_hasIdentityMatrix },
+        {"nHasOverlappingRendering", "(J)Z",
+         (void*)android_view_RenderNode_hasOverlappingRendering},
+        {"nGetClipToOutline", "(J)Z", (void*)android_view_RenderNode_getClipToOutline},
+        {"nGetAlpha", "(J)F", (void*)android_view_RenderNode_getAlpha},
+        {"nGetCameraDistance", "(J)F", (void*)android_view_RenderNode_getCameraDistance},
+        {"nGetScaleX", "(J)F", (void*)android_view_RenderNode_getScaleX},
+        {"nGetScaleY", "(J)F", (void*)android_view_RenderNode_getScaleY},
+        {"nGetElevation", "(J)F", (void*)android_view_RenderNode_getElevation},
+        {"nGetTranslationX", "(J)F", (void*)android_view_RenderNode_getTranslationX},
+        {"nGetTranslationY", "(J)F", (void*)android_view_RenderNode_getTranslationY},
+        {"nGetTranslationZ", "(J)F", (void*)android_view_RenderNode_getTranslationZ},
+        {"nGetRotation", "(J)F", (void*)android_view_RenderNode_getRotation},
+        {"nGetRotationX", "(J)F", (void*)android_view_RenderNode_getRotationX},
+        {"nGetRotationY", "(J)F", (void*)android_view_RenderNode_getRotationY},
+        {"nIsPivotExplicitlySet", "(J)Z", (void*)android_view_RenderNode_isPivotExplicitlySet},
+        {"nHasIdentityMatrix", "(J)Z", (void*)android_view_RenderNode_hasIdentityMatrix},
 
-    { "nGetTransformMatrix",       "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
-    { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
+        {"nGetTransformMatrix", "(JJ)V", (void*)android_view_RenderNode_getTransformMatrix},
+        {"nGetInverseTransformMatrix", "(JJ)V",
+         (void*)android_view_RenderNode_getInverseTransformMatrix},
 
-    { "nGetPivotX",                "(J)F",  (void*) android_view_RenderNode_getPivotX },
-    { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
-    { "nGetWidth",                 "(J)I",  (void*) android_view_RenderNode_getWidth },
-    { "nGetHeight",                "(J)I",  (void*) android_view_RenderNode_getHeight },
-    { "nSetAllowForceDark",        "(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark },
-    { "nGetAllowForceDark",        "(J)Z",  (void*) android_view_RenderNode_getAllowForceDark },
-    { "nGetUniqueId",              "(J)J",  (void*) android_view_RenderNode_getUniqueId },
+        {"nGetPivotX", "(J)F", (void*)android_view_RenderNode_getPivotX},
+        {"nGetPivotY", "(J)F", (void*)android_view_RenderNode_getPivotY},
+        {"nGetWidth", "(J)I", (void*)android_view_RenderNode_getWidth},
+        {"nGetHeight", "(J)I", (void*)android_view_RenderNode_getHeight},
+        {"nSetAllowForceDark", "(JZ)Z", (void*)android_view_RenderNode_setAllowForceDark},
+        {"nGetAllowForceDark", "(J)Z", (void*)android_view_RenderNode_getAllowForceDark},
+        {"nGetUniqueId", "(J)J", (void*)android_view_RenderNode_getUniqueId},
 };
 
 int register_android_view_RenderNode(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index c010212..cb0ff8d 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -169,8 +169,8 @@
     displayList->mProjectedOutline = nullptr;
 }
 
-static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
-                            SkPaint* paint) {
+static bool layerNeedsPaint(const sk_sp<SkImage>& snapshotImage, const LayerProperties& properties,
+                            float alphaMultiplier, SkPaint* paint) {
     if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
         properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
         properties.getImageFilter() != nullptr || !properties.getStretchEffect().isEmpty()) {
@@ -179,7 +179,8 @@
         paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
 
         sk_sp<SkImageFilter> imageFilter = sk_ref_sp(properties.getImageFilter());
-        sk_sp<SkImageFilter> stretchFilter = properties.getStretchEffect().getImageFilter();
+        sk_sp<SkImageFilter> stretchFilter =
+                properties.getStretchEffect().getImageFilter(snapshotImage);
         sk_sp<SkImageFilter> filter;
         if (imageFilter && stretchFilter) {
             filter = SkImageFilters::Compose(
@@ -240,7 +241,8 @@
         if (renderNode->getLayerSurface() && mComposeLayer) {
             SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
             SkPaint paint;
-            layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
+            sk_sp<SkImage> snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot();
+            layerNeedsPaint(snapshotImage, layerProperties, alphaMultiplier, &paint);
             SkSamplingOptions sampling(SkFilterMode::kLinear);
 
             // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
@@ -254,8 +256,8 @@
                 canvas->drawAnnotation(bounds, String8::format(
                     "SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
             }
-            canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot(), bounds,
-                                  bounds, sampling, &paint, SkCanvas::kStrict_SrcRectConstraint);
+            canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
+                                  SkCanvas::kStrict_SrcRectConstraint);
 
             if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
                 renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 389fe7e..50eea31 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -105,7 +105,6 @@
     LightingInfo::updateLighting(lightGeometry, lightInfo);
     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
                 SkMatrix::I());
-    layerUpdateQueue->clear();
 
     // Draw visual debugging features
     if (CC_UNLIKELY(Properties::showDirtyRegions ||
@@ -113,9 +112,14 @@
         SkCanvas* profileCanvas = surface->getCanvas();
         SkiaProfileRenderer profileRenderer(profileCanvas);
         profiler->draw(profileRenderer);
-        profileCanvas->flush();
     }
 
+    {
+        ATRACE_NAME("flush commands");
+        surface->flushAndSubmit();
+    }
+    layerUpdateQueue->clear();
+
     // Log memory statistics
     if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
         dumpResourceCacheUsage();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6456e36..1f73ac9 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -454,9 +454,6 @@
         renderOverdraw(clip, nodes, contentDrawBounds, surface, preTransform);
     }
 
-    ATRACE_NAME("flush commands");
-    surface->flushAndSubmit();
-
     Properties::skpCaptureEnabled = previousSkpEnabled;
 }
 
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index af7271e..61f9960 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -176,9 +176,6 @@
     if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) {
         paint.setBlendMode(SkBlendMode::kDstOut);
     }
-
-    // disabling AA on bitmap draws matches legacy HWUI behavior
-    paint.setAntiAlias(false);
 }
 
 static SkFilterMode Paint_to_filter(const SkPaint& paint) {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ad6363b..1bd943f 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -17,14 +17,15 @@
 #include "SkiaVulkanPipeline.h"
 
 #include "DeferredLayerUpdater.h"
+#include "LightingInfo.h"
 #include "Readback.h"
 #include "ShaderCache.h"
-#include "LightingInfo.h"
 #include "SkiaPipeline.h"
 #include "SkiaProfileRenderer.h"
 #include "VkInteropFunctorDrawable.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
+#include "utils/TraceUtils.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -73,8 +74,6 @@
     LightingInfo::updateLighting(lightGeometry, lightInfo);
     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
                 mVkSurface->getCurrentPreTransform());
-    ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
-    layerUpdateQueue->clear();
 
     // Draw visual debugging features
     if (CC_UNLIKELY(Properties::showDirtyRegions ||
@@ -82,9 +81,14 @@
         SkCanvas* profileCanvas = backBuffer->getCanvas();
         SkiaProfileRenderer profileRenderer(profileCanvas);
         profiler->draw(profileRenderer);
-        profileCanvas->flush();
     }
 
+    {
+        ATRACE_NAME("flush commands");
+        mVkManager.finishFrame(backBuffer.get());
+    }
+    layerUpdateQueue->clear();
+
     // Log memory statistics
     if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
         dumpResourceCacheUsage();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 3e7ce36..e93824d 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -31,6 +31,7 @@
 
 #include "Properties.h"
 #include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
 #include "renderstate/RenderState.h"
 #include "utils/TraceUtils.h"
 
@@ -476,17 +477,10 @@
     }
 }
 
-void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
-    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
-        ATRACE_NAME("Finishing GPU work");
-        mDeviceWaitIdle(mDevice);
-    }
-
-    VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
-    if (!bufferInfo) {
-        // If VulkanSurface::dequeueNativeBuffer failed earlier, then swapBuffers is a no-op.
-        return;
-    }
+void VulkanManager::finishFrame(SkSurface* surface) {
+    ATRACE_NAME("Vulkan finish frame");
+    ALOGE_IF(mSwapSemaphore != VK_NULL_HANDLE || mDestroySemaphoreContext != nullptr,
+             "finishFrame already has an outstanding semaphore");
 
     VkExportSemaphoreCreateInfo exportInfo;
     exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
@@ -499,32 +493,52 @@
     semaphoreInfo.flags = 0;
     VkSemaphore semaphore;
     VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
-    ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
+    ALOGE_IF(VK_SUCCESS != err, "VulkanManager::makeSwapSemaphore(): Failed to create semaphore");
 
     GrBackendSemaphore backendSemaphore;
     backendSemaphore.initVulkan(semaphore);
 
-    int fenceFd = -1;
-    DestroySemaphoreInfo* destroyInfo =
-            new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
     GrFlushInfo flushInfo;
-    flushInfo.fNumSemaphores = 1;
-    flushInfo.fSignalSemaphores = &backendSemaphore;
-    flushInfo.fFinishedProc = destroy_semaphore;
-    flushInfo.fFinishedContext = destroyInfo;
-    GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush(
-            SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
-    GrDirectContext* context = GrAsDirectContext(bufferInfo->skSurface->recordingContext());
+    if (err == VK_SUCCESS) {
+        mDestroySemaphoreContext = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
+        flushInfo.fNumSemaphores = 1;
+        flushInfo.fSignalSemaphores = &backendSemaphore;
+        flushInfo.fFinishedProc = destroy_semaphore;
+        flushInfo.fFinishedContext = mDestroySemaphoreContext;
+    } else {
+        semaphore = VK_NULL_HANDLE;
+    }
+    GrSemaphoresSubmitted submitted =
+            surface->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
+    GrDirectContext* context = GrAsDirectContext(surface->recordingContext());
     ALOGE_IF(!context, "Surface is not backed by gpu");
     context->submit();
-    if (submitted == GrSemaphoresSubmitted::kYes) {
+    if (semaphore != VK_NULL_HANDLE) {
+        if (submitted == GrSemaphoresSubmitted::kYes) {
+            mSwapSemaphore = semaphore;
+        } else {
+            destroy_semaphore(mDestroySemaphoreContext);
+            mDestroySemaphoreContext = nullptr;
+        }
+    }
+    skiapipeline::ShaderCache::get().onVkFrameFlushed(context);
+}
+
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+        ATRACE_NAME("Finishing GPU work");
+        mDeviceWaitIdle(mDevice);
+    }
+
+    int fenceFd = -1;
+    if (mSwapSemaphore != VK_NULL_HANDLE) {
         VkSemaphoreGetFdInfoKHR getFdInfo;
         getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
         getFdInfo.pNext = nullptr;
-        getFdInfo.semaphore = semaphore;
+        getFdInfo.semaphore = mSwapSemaphore;
         getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
 
-        err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+        VkResult err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
         ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
     } else {
         ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
@@ -532,9 +546,11 @@
         std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
         mQueueWaitIdle(mGraphicsQueue);
     }
-    destroy_semaphore(destroyInfo);
+    destroy_semaphore(mDestroySemaphoreContext);
 
     surface->presentCurrentBuffer(dirtyRect, fenceFd);
+    mSwapSemaphore = VK_NULL_HANDLE;
+    mDestroySemaphoreContext = nullptr;
 }
 
 void VulkanManager::destroySurface(VulkanSurface* surface) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 121afc9..0912369 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -69,6 +69,7 @@
     void destroySurface(VulkanSurface* surface);
 
     Frame dequeueNextBuffer(VulkanSurface* surface);
+    void finishFrame(SkSurface* surface);
     void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
 
     // Inserts a wait on fence command into the Vulkan command buffer.
@@ -200,6 +201,9 @@
     SwapBehavior mSwapBehavior = SwapBehavior::Discard;
     GrVkExtensions mExtensions;
     uint32_t mDriverVersion = 0;
+
+    VkSemaphore mSwapSemaphore = VK_NULL_HANDLE;
+    void* mDestroySemaphoreContext = nullptr;
 };
 
 } /* namespace renderthread */
diff --git a/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
index cee3635..8186fb7 100644
--- a/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
@@ -32,8 +32,8 @@
      * Unique vendor ID. Identifies the engine the sound model
      * was build for */
     String vendorUuid;
-    /** Opaque data transparent to Android framework */
-    ParcelFileDescriptor data;
+    /** Opaque data transparent to Android framework. May be null if dataSize is 0. */
+    @nullable ParcelFileDescriptor data;
     /** Size of the above data, in bytes. */
     int dataSize;
 }
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index ff9fd41..ca175b4 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -195,6 +195,61 @@
         @NonNull public static final Key<Integer> KEY_AUDIO_ENCODING =
                 createKey("audio-encoding", Integer.class);
 
+
+        /**
+         * A key representing the audio presentation id being decoded by a next generation
+         * audio decoder.
+         *
+         * An Integer value representing presentation id.
+         *
+         * @see AudioPresentation#getPresentationId()
+         */
+        @NonNull public static final Key<Integer> KEY_PRESENTATION_ID =
+                createKey("presentation-id", Integer.class);
+
+         /**
+         * A key representing the audio program id being decoded by a next generation
+         * audio decoder.
+         *
+         * An Integer value representing program id.
+         *
+         * @see AudioPresentation#getProgramId()
+         */
+        @NonNull public static final Key<Integer> KEY_PROGRAM_ID =
+                createKey("program-id", Integer.class);
+
+
+         /**
+         * A key representing the audio presentation content classifier being rendered
+         * by a next generation audio decoder.
+         *
+         * An Integer value representing presentation content classifier.
+         *
+         * @see AudioPresentation.ContentClassifier
+         * One of {@link AudioPresentation#CONTENT_UNKNOWN},
+         *     {@link AudioPresentation#CONTENT_MAIN},
+         *     {@link AudioPresentation#CONTENT_MUSIC_AND_EFFECTS},
+         *     {@link AudioPresentation#CONTENT_VISUALLY_IMPAIRED},
+         *     {@link AudioPresentation#CONTENT_HEARING_IMPAIRED},
+         *     {@link AudioPresentation#CONTENT_DIALOG},
+         *     {@link AudioPresentation#CONTENT_COMMENTARY},
+         *     {@link AudioPresentation#CONTENT_EMERGENCY},
+         *     {@link AudioPresentation#CONTENT_VOICEOVER}.
+         */
+        @NonNull public static final Key<Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER =
+                createKey("presentation-content-classifier", Integer.class);
+
+        /**
+         * A key representing the audio presentation language being rendered by a next
+         * generation audio decoder.
+         *
+         * A String value representing ISO 639-2 (three letter code).
+         *
+         * @see AudioPresentation#getLocale()
+         */
+        @NonNull public static final Key<String> KEY_PRESENTATION_LANGUAGE =
+                createKey("presentation-language", String.class);
+
         private Format() {} // delete constructor
     }
 
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index 894fbba..47358be 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -57,6 +57,64 @@
     /** @hide */
     @IntDef(
         value = {
+        CONTENT_UNKNOWN,
+        CONTENT_MAIN,
+        CONTENT_MUSIC_AND_EFFECTS,
+        CONTENT_VISUALLY_IMPAIRED,
+        CONTENT_HEARING_IMPAIRED,
+        CONTENT_DIALOG,
+        CONTENT_COMMENTARY,
+        CONTENT_EMERGENCY,
+        CONTENT_VOICEOVER,
+    })
+
+    /**
+     * The ContentClassifier int definitions represent the AudioPresentation content
+     * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1)
+    */
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ContentClassifier {}
+
+    /**
+     * Audio presentation classifier: Unknown.
+     */
+    public static final int CONTENT_UNKNOWN                 = -1;
+    /**
+     * Audio presentation classifier: Complete main.
+     */
+    public static final int CONTENT_MAIN                    = 0;
+    /**
+     * Audio presentation content classifier: Music and effects.
+     */
+    public static final int CONTENT_MUSIC_AND_EFFECTS       = 1;
+    /**
+     * Audio presentation content classifier: Visually impaired.
+     */
+    public static final int CONTENT_VISUALLY_IMPAIRED       = 2;
+    /**
+     * Audio presentation content classifier: Hearing impaired.
+     */
+    public static final int CONTENT_HEARING_IMPAIRED        = 3;
+    /**
+     * Audio presentation content classifier: Dialog.
+     */
+    public static final int CONTENT_DIALOG                  = 4;
+    /**
+     * Audio presentation content classifier: Commentary.
+     */
+    public static final int CONTENT_COMMENTARY              = 5;
+    /**
+     * Audio presentation content classifier: Emergency.
+     */
+    public static final int CONTENT_EMERGENCY               = 6;
+    /**
+     * Audio presentation content classifier: Voice over.
+     */
+    public static final int CONTENT_VOICEOVER               = 7;
+
+    /** @hide */
+    @IntDef(
+        value = {
             MASTERING_NOT_INDICATED,
             MASTERED_FOR_STEREO,
             MASTERED_FOR_SURROUND,
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index b196437..bf04b66 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -275,6 +275,12 @@
     private AudioAttributes mAudioAttributes;
     private boolean mIsSubmixFullVolume = false;
 
+    /**
+     * The log session id used for metrics.
+     * A null or empty string here means it is not set.
+     */
+    private String mLogSessionId;
+
     //---------------------------------------------------------
     // Constructor, Finalize
     //--------------------
@@ -1913,6 +1919,25 @@
         return native_set_preferred_microphone_field_dimension(zoom) == AudioSystem.SUCCESS;
     }
 
+    /**
+     * Sets a string handle to this AudioRecord for metrics collection.
+     *
+     * @param logSessionId a string which is used to identify this object
+     *        to the metrics service.  Proper generated Ids must be obtained
+     *        from the Java metrics service and should be considered opaque.
+     *        Use null to remove the logSessionId association.
+     * @throws IllegalStateException if AudioRecord not initialized.
+     *
+     * @hide
+     */
+    public void setLogSessionId(@Nullable String logSessionId) {
+        if (mState == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("AudioRecord not initialized");
+        }
+        native_setLogSessionId(logSessionId);
+        mLogSessionId = logSessionId;
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
@@ -2072,6 +2097,8 @@
     private native int native_set_preferred_microphone_direction(int direction);
     private native int native_set_preferred_microphone_field_dimension(float zoom);
 
+    private native void native_setLogSessionId(@Nullable String logSessionId);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 58174a0..88731d2 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -567,6 +567,7 @@
 
     /**
      * The log session id used for metrics.
+     * A null or empty string here means it is not set.
      */
     private String mLogSessionId;
 
@@ -928,12 +929,21 @@
         private final int mSyncId;
 
         /**
+         * A special content id for {@link #TunerConfiguration(int, int)}
+         * indicating audio is delivered
+         * from an {@code AudioTrack} write, not tunneled from the tuner stack.
+         */
+        public static final int CONTENT_ID_NONE = 0;
+
+        /**
          * Constructs a TunerConfiguration instance for use in {@link AudioTrack.Builder}
          *
          * @param contentId selects the audio stream to use.
          *     The contentId may be obtained from
-         *     {@link android.media.tv.tuner.filter.Filter#getId()}.
-         *     This is always a positive number.
+         *     {@link android.media.tv.tuner.filter.Filter#getId()},
+         *     such obtained id is always a positive number.
+         *     If audio is to be delivered through an {@code AudioTrack} write
+         *     then {@code CONTENT_ID_NONE} may be used.
          * @param syncId selects the clock to use for synchronization
          *     of audio with other streams such as video.
          *     The syncId may be obtained from
@@ -942,10 +952,10 @@
          */
         @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
         public TunerConfiguration(
-                @IntRange(from = 1) int contentId, @IntRange(from = 1)int syncId) {
-            if (contentId < 1) {
+                @IntRange(from = 0) int contentId, @IntRange(from = 1)int syncId) {
+            if (contentId < 0) {
                 throw new IllegalArgumentException(
-                        "contentId " + contentId + " must be positive");
+                        "contentId " + contentId + " must be positive or CONTENT_ID_NONE");
             }
             if (syncId < 1) {
                 throw new IllegalArgumentException("syncId " + syncId + " must be positive");
@@ -3978,12 +3988,14 @@
      * Sets a string handle to this AudioTrack for metrics collection.
      *
      * @param logSessionId a string which is used to identify this object
-     *        to the metrics service.
+     *        to the metrics service.  Proper generated Ids must be obtained
+     *        from the Java metrics service and should be considered opaque.
+     *        Use null to remove the logSessionId association.
      * @throws IllegalStateException if AudioTrack not initialized.
      *
      * @hide
      */
-    public void setLogSessionId(@NonNull String logSessionId) {
+    public void setLogSessionId(@Nullable String logSessionId) {
         if (mState == STATE_UNINITIALIZED) {
             throw new IllegalStateException("track not initialized");
         }
@@ -4226,7 +4238,7 @@
     private native int native_get_audio_description_mix_level_db(float[] level);
     private native int native_set_dual_mono_mode(int dualMonoMode);
     private native int native_get_dual_mono_mode(int[] dualMonoMode);
-    private native void native_setLogSessionId(@NonNull String logSessionId);
+    private native void native_setLogSessionId(@Nullable String logSessionId);
 
     /**
      * Sets the audio service Player Interface Id.
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 56f6c45..53f6fe2 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -445,8 +445,7 @@
         jniThrowException(env, "android/media/DeniedByServerException", msg);
         return true;
     } else if (err == DEAD_OBJECT) {
-        jniThrowException(env, "android/media/MediaDrmResetException",
-                "mediaserver died");
+        jniThrowException(env, "android/media/MediaDrmResetException", msg);
         return true;
     } else if (isSessionException(err)) {
         throwSessionException(env, msg, err);
@@ -967,10 +966,12 @@
     status_t err = drm->initCheck();
 
     if (err != OK) {
+        auto logs(DrmUtils::gLogBuf.getLogs());
+        auto msg(DrmUtils::GetExceptionMessage(err, "Failed to instantiate drm object", logs));
         jniThrowException(
                 env,
                 "android/media/UnsupportedSchemeException",
-                "Failed to instantiate drm object.");
+                msg.c_str());
         return;
     }
 
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index b7cde57..7562d39 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1128,7 +1128,7 @@
             bool isHighPriority = message.isHighPriority();
             env->CallVoidMethod(
                     frontend,
-                    env->GetMethodID(clazz, "onPriorityReported", "(B)V"),
+                    env->GetMethodID(clazz, "onPriorityReported", "(Z)V"),
                     isHighPriority);
             break;
         }
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index e620dfb..8b44887 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -107,12 +107,10 @@
                 String callingPackage,
                 IFindDeviceCallback findCallback,
                 AndroidFuture serviceCallback) {
-            if (DEBUG) {
-                Log.i(LOG_TAG,
-                        "startDiscovery() called with: filter = [" + request
-                                + "], findCallback = [" + findCallback + "]"
-                                + "], serviceCallback = [" + serviceCallback + "]");
-            }
+            Log.i(LOG_TAG,
+                    "startDiscovery() called with: filter = [" + request
+                            + "], findCallback = [" + findCallback + "]"
+                            + "], serviceCallback = [" + serviceCallback + "]");
             mFindCallback = findCallback;
             mServiceCallback = serviceCallback;
             Handler.getMain().sendMessage(obtainMessage(
@@ -127,7 +125,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (DEBUG) Log.i(LOG_TAG, "onBind(" + intent + ")");
+        Log.i(LOG_TAG, "onBind(" + intent + ")");
         return mBinder.asBinder();
     }
 
@@ -135,7 +133,7 @@
     public void onCreate() {
         super.onCreate();
 
-        if (DEBUG) Log.i(LOG_TAG, "onCreate()");
+        Log.i(LOG_TAG, "onCreate()");
 
         mBluetoothManager = getSystemService(BluetoothManager.class);
         mBluetoothAdapter = mBluetoothManager.getAdapter();
@@ -160,7 +158,9 @@
                     = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter);
 
             reset();
-        } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+        } else {
+            Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+        }
 
         if (!ArrayUtils.isEmpty(mDevicesFound)) {
             onReadyToShowUI();
@@ -197,17 +197,20 @@
             final IntentFilter intentFilter = new IntentFilter();
             intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
 
+            Log.i(LOG_TAG, "registerReceiver(BluetoothDevice.ACTION_FOUND)");
             mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
             registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
             mBluetoothAdapter.startDiscovery();
         }
 
         if (shouldScan(mBLEFilters) && mBLEScanner != null) {
+            Log.i(LOG_TAG, "BLEScanner.startScan");
             mBLEScanCallback = new BLEScanCallback();
             mBLEScanner.startScan(mBLEScanFilters, mDefaultScanSettings, mBLEScanCallback);
         }
 
         if (shouldScan(mWifiFilters)) {
+            Log.i(LOG_TAG, "registerReceiver(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)");
             mWifiBroadcastReceiver = new WifiBroadcastReceiver();
             registerReceiver(mWifiBroadcastReceiver,
                     new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
@@ -225,7 +228,7 @@
 
     @MainThread
     private void reset() {
-        if (DEBUG) Log.i(LOG_TAG, "reset()");
+        Log.i(LOG_TAG, "reset()");
         stopScan();
         mDevicesFound.clear();
         mSelectedDevice = null;
@@ -234,12 +237,13 @@
 
     @Override
     public boolean onUnbind(Intent intent) {
+        Log.i(LOG_TAG, "onUnbind(intent = " + intent + ")");
         stopScan();
         return super.onUnbind(intent);
     }
 
     private void stopScan() {
-        if (DEBUG) Log.i(LOG_TAG, "stopScan()");
+        Log.i(LOG_TAG, "stopScan()");
 
         if (!mIsScanning) return;
         mIsScanning = false;
diff --git a/core/java/android/net/QosFilterParcelable.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl
similarity index 100%
rename from core/java/android/net/QosFilterParcelable.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl
diff --git a/core/java/android/net/QosSession.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl
similarity index 100%
rename from core/java/android/net/QosSession.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl
diff --git a/core/java/android/net/QosSocketInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl
similarity index 100%
rename from core/java/android/net/QosSocketInfo.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index 31b8fc8..a8f1a4d 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -401,16 +401,6 @@
     method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
   }
 
-  public final class Proxy {
-    ctor public Proxy();
-    method @Deprecated public static String getDefaultHost();
-    method @Deprecated public static int getDefaultPort();
-    method @Deprecated public static String getHost(android.content.Context);
-    method @Deprecated public static int getPort(android.content.Context);
-    field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
-    field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
-  }
-
   public class ProxyInfo implements android.os.Parcelable {
     ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
     method public static android.net.ProxyInfo buildDirectProxy(String, int);
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 3af855e..a9fd6f2 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -23,10 +23,6 @@
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
 
-  public final class Proxy {
-    method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
-  }
-
   public final class TcpRepairWindow {
     ctor public TcpRepairWindow(int, int, int, int, int, int);
     field public final int maxWindow;
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 41ebc57..f5972fa 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -2,7 +2,7 @@
 package android.net {
 
   public class CaptivePortal implements android.os.Parcelable {
-    method public void logEvent(int, @NonNull String);
+    method @Deprecated public void logEvent(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
     method public void useNetwork();
     field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
@@ -308,6 +308,9 @@
     field public static final int ID_NONE = -1; // 0xffffffff
   }
 
+  public class NetworkReleasedException extends java.lang.Exception {
+  }
+
   public class NetworkRequest implements android.os.Parcelable {
     method @Nullable public String getRequestorPackageName();
     method public int getRequestorUid();
@@ -317,6 +320,47 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
   }
 
+  public abstract class QosCallback {
+    ctor public QosCallback();
+    method public void onError(@NonNull android.net.QosCallbackException);
+    method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+    method public void onQosSessionLost(@NonNull android.net.QosSession);
+  }
+
+  public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+  }
+
+  public final class QosCallbackException extends java.lang.Exception {
+  }
+
+  public abstract class QosFilter {
+    method @NonNull public abstract android.net.Network getNetwork();
+    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+  }
+
+  public final class QosSession implements android.os.Parcelable {
+    ctor public QosSession(int, int);
+    method public int describeContents();
+    method public int getSessionId();
+    method public int getSessionType();
+    method public long getUniqueId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+    field public static final int TYPE_EPS_BEARER = 1; // 0x1
+  }
+
+  public interface QosSessionAttributes {
+  }
+
+  public final class QosSocketInfo implements android.os.Parcelable {
+    ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+    method public int describeContents();
+    method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+    method @NonNull public android.net.Network getNetwork();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+  }
+
   public final class RouteInfo implements android.os.Parcelable {
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -331,6 +375,12 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
+  public class SocketLocalAddressChangedException extends java.lang.Exception {
+  }
+
+  public class SocketNotBoundException extends java.lang.Exception {
+  }
+
   public final class StaticIpConfiguration implements android.os.Parcelable {
     ctor public StaticIpConfiguration();
     ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
@@ -392,16 +442,3 @@
 
 }
 
-package android.net.util {
-
-  public final class SocketUtils {
-    method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
-    method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
-    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
-    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
-  }
-
-}
-
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortal.java b/packages/Connectivity/framework/src/android/net/CaptivePortal.java
index 269bbf2..4a7b601 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortal.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortal.java
@@ -160,12 +160,11 @@
      * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto.
      * @param packageName captive portal application package name.
      * @hide
+     * @deprecated The event will not be logged in Android S and above. The
+     * caller is migrating to statsd.
      */
+    @Deprecated
     @SystemApi
     public void logEvent(int eventId, @NonNull String packageName) {
-        try {
-            ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
-        } catch (RemoteException e) {
-        }
     }
 }
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index e7ab0a1..39ec2edc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -2245,31 +2245,6 @@
         }
     }
 
-    /* TODO: These permissions checks don't belong in client-side code. Move them to
-     * services.jar, possibly in com.android.server.net. */
-
-    /** {@hide} */
-    public static final void enforceChangePermission(Context context,
-            String callingPkg, String callingAttributionTag) {
-        int uid = Binder.getCallingUid();
-        checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg,
-                callingAttributionTag, true /* throwException */);
-    }
-
-    /**
-     * Check if the package is a allowed to change the network state. This also accounts that such
-     * an access happened.
-     *
-     * @return {@code true} iff the package is allowed to change the network state.
-     */
-    // TODO: Remove method and replace with direct call once R code is pushed to AOSP
-    private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context,
-            int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag,
-            boolean throwException) {
-        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage,
-                callingAttributionTag, throwException);
-    }
-
     /**
      * Check if the package is a allowed to write settings. This also accounts that such an access
      * happened.
diff --git a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
index fe21905..e35f8d4 100644
--- a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
+++ b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
@@ -23,5 +23,4 @@
 oneway interface ICaptivePortal {
     void appRequest(int request);
     void appResponse(int response);
-    void logEvent(int eventId, String packageName);
 }
diff --git a/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl b/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
similarity index 100%
rename from core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
rename to packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
diff --git a/core/java/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
similarity index 100%
rename from core/java/android/net/IQosCallback.aidl
rename to packages/Connectivity/framework/src/android/net/IQosCallback.aidl
diff --git a/core/java/android/net/NetworkReleasedException.java b/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java
similarity index 100%
rename from core/java/android/net/NetworkReleasedException.java
rename to packages/Connectivity/framework/src/android/net/NetworkReleasedException.java
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index b5e8a61..9e42bbe 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -87,22 +87,6 @@
     public static native int bindSocketToNetwork(FileDescriptor fd, int netId);
 
     /**
-     * Protect {@code fd} from VPN connections.  After protecting, data sent through
-     * this socket will go directly to the underlying network, so its traffic will not be
-     * forwarded through the VPN.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
-            publicAlternatives = "Use {@link android.net.VpnService#protect} instead.")
-    public static native boolean protectFromVpn(FileDescriptor fd);
-
-    /**
-     * Protect {@code socketfd} from VPN connections.  After protecting, data sent through
-     * this socket will go directly to the underlying network, so its traffic will not be
-     * forwarded through the VPN.
-     */
-    public native static boolean protectFromVpn(int socketfd);
-
-    /**
      * Determine if {@code uid} can access network designated by {@code netId}.
      * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
      */
diff --git a/core/java/android/net/QosCallback.java b/packages/Connectivity/framework/src/android/net/QosCallback.java
similarity index 100%
rename from core/java/android/net/QosCallback.java
rename to packages/Connectivity/framework/src/android/net/QosCallback.java
diff --git a/core/java/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
similarity index 100%
rename from core/java/android/net/QosCallbackConnection.java
rename to packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
diff --git a/core/java/android/net/QosCallbackException.java b/packages/Connectivity/framework/src/android/net/QosCallbackException.java
similarity index 100%
rename from core/java/android/net/QosCallbackException.java
rename to packages/Connectivity/framework/src/android/net/QosCallbackException.java
diff --git a/core/java/android/net/QosFilter.java b/packages/Connectivity/framework/src/android/net/QosFilter.java
similarity index 100%
rename from core/java/android/net/QosFilter.java
rename to packages/Connectivity/framework/src/android/net/QosFilter.java
diff --git a/core/java/android/net/QosFilterParcelable.java b/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java
similarity index 100%
rename from core/java/android/net/QosFilterParcelable.java
rename to packages/Connectivity/framework/src/android/net/QosFilterParcelable.java
diff --git a/core/java/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java
similarity index 100%
rename from core/java/android/net/QosSession.java
rename to packages/Connectivity/framework/src/android/net/QosSession.java
diff --git a/core/java/android/net/QosSessionAttributes.java b/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java
similarity index 100%
rename from core/java/android/net/QosSessionAttributes.java
rename to packages/Connectivity/framework/src/android/net/QosSessionAttributes.java
diff --git a/core/java/android/net/QosSocketFilter.java b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
similarity index 100%
rename from core/java/android/net/QosSocketFilter.java
rename to packages/Connectivity/framework/src/android/net/QosSocketFilter.java
diff --git a/core/java/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
similarity index 100%
rename from core/java/android/net/QosSocketInfo.java
rename to packages/Connectivity/framework/src/android/net/QosSocketInfo.java
diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java
similarity index 100%
rename from core/java/android/net/SocketLocalAddressChangedException.java
rename to packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java
diff --git a/core/java/android/net/SocketNotBoundException.java b/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java
similarity index 100%
rename from core/java/android/net/SocketNotBoundException.java
rename to packages/Connectivity/framework/src/android/net/SocketNotBoundException.java
diff --git a/core/java/android/net/UidRange.aidl b/packages/Connectivity/framework/src/android/net/UidRange.aidl
similarity index 100%
rename from core/java/android/net/UidRange.aidl
rename to packages/Connectivity/framework/src/android/net/UidRange.aidl
diff --git a/core/java/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java
similarity index 86%
rename from core/java/android/net/UidRange.java
rename to packages/Connectivity/framework/src/android/net/UidRange.java
index f0e7da7..26518d3 100644
--- a/core/java/android/net/UidRange.java
+++ b/packages/Connectivity/framework/src/android/net/UidRange.java
@@ -16,8 +16,6 @@
 
 package android.net;
 
-import static android.os.UserHandle.PER_USER_RANGE;
-
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -52,14 +50,15 @@
 
     /** Returns the smallest user Id which is contained in this UidRange */
     public int getStartUser() {
-        return start / PER_USER_RANGE;
+        return UserHandle.getUserHandleForUid(start).getIdentifier();
     }
 
     /** Returns the largest user Id which is contained in this UidRange */
     public int getEndUser() {
-        return stop / PER_USER_RANGE;
+        return UserHandle.getUserHandleForUid(stop).getIdentifier();
     }
 
+    /** Returns whether the UidRange contains the specified UID. */
     public boolean contains(int uid) {
         return start <= uid && uid <= stop;
     }
@@ -72,7 +71,7 @@
     }
 
     /**
-     * @return {@code true} if this range contains every UID contained by the {@param other} range.
+     * @return {@code true} if this range contains every UID contained by the {@code other} range.
      */
     public boolean containsRange(UidRange other) {
         return start <= other.start && other.stop <= stop;
@@ -118,18 +117,18 @@
     }
 
     public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
-        new Creator<UidRange>() {
-            @Override
-            public UidRange createFromParcel(Parcel in) {
-                int start = in.readInt();
-                int stop = in.readInt();
+            new Creator<UidRange>() {
+        @Override
+        public UidRange createFromParcel(Parcel in) {
+            int start = in.readInt();
+            int stop = in.readInt();
 
-                return new UidRange(start, stop);
-            }
-            @Override
-            public UidRange[] newArray(int size) {
-                return new UidRange[size];
-            }
+            return new UidRange(start, stop);
+        }
+        @Override
+        public UidRange[] newArray(int size) {
+            return new UidRange[size];
+        }
     };
 
     /**
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index f20b89f..e65b7b4 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -63,6 +63,7 @@
         "unsupportedappusage",
     ],
     static_libs: [
+        "modules-utils-os",
         "net-utils-device-common",
         "net-utils-framework-common",
         "netd-client",
diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt
index ef53ebb..d8205bf 100644
--- a/packages/Connectivity/service/jarjar-rules.txt
+++ b/packages/Connectivity/service/jarjar-rules.txt
@@ -1 +1,2 @@
-rule com.android.net.module.util.** com.android.connectivity.util.@1
\ No newline at end of file
+rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
+rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 7f19662..c1dca5d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -394,16 +394,20 @@
     }
 
     private void executeNotifyIfInUseCommand() {
-        int status = getStatus();
-
-        if (status == STATUS_IN_USE) {
-            startForeground(NOTIFICATION_ID,
-                    buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
-        } else if (status == STATUS_READY) {
-            startForeground(NOTIFICATION_ID,
-                    buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
-        } else {
-            stopSelf();
+        switch (getStatus()) {
+            case STATUS_IN_USE:
+                startForeground(NOTIFICATION_ID,
+                        buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
+                break;
+            case STATUS_READY:
+                startForeground(NOTIFICATION_ID,
+                        buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
+                break;
+            case STATUS_IN_PROGRESS:
+                break;
+            case STATUS_NOT_STARTED:
+            default:
+                stopSelf();
         }
     }
 
diff --git a/packages/LocalTransport/OWNERS b/packages/LocalTransport/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/LocalTransport/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 139c8e5..63edc77 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -165,6 +165,9 @@
         if (mParameters.isDeviceTransfer()) {
             flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER;
         }
+        if (mParameters.isEncrypted()) {
+            flags |= BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+        }
         return flags;
     }
 
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 2946db3..1ba1bc6 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -28,10 +28,12 @@
     private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
     private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
     private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
+    private static final String KEY_IS_ENCRYPTED = "is_encrypted";
 
     private boolean mFakeEncryptionFlag;
     private boolean mIsNonIncrementalOnly;
     private boolean mIsDeviceTransfer;
+    private boolean mIsEncrypted;
 
     public LocalTransportParameters(Handler handler, ContentResolver resolver) {
         super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -49,6 +51,10 @@
         return mIsDeviceTransfer;
     }
 
+    boolean isEncrypted() {
+        return mIsEncrypted;
+    }
+
     public String getSettingValue(ContentResolver resolver) {
         return Settings.Secure.getString(resolver, SETTING);
     }
@@ -57,5 +63,6 @@
         mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
         mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
         mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
+        mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false);
     }
 }
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml
new file mode 100644
index 0000000..c799b99
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+-->
+<!-- The main content view -->
+<LinearLayout
+    android:id="@+id/content_parent"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
+    android:transitionGroup="true"
+    android:orientation="vertical">
+    <Toolbar
+        android:id="@+id/action_bar"
+        style="?android:attr/actionBarStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:theme="?android:attr/actionBarTheme" />
+    <FrameLayout
+        android:id="@+id/content_frame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 637805f..ad94cd03 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -24,6 +24,7 @@
 import android.widget.Toolbar;
 
 import androidx.annotation.Nullable;
+import androidx.core.os.BuildCompat;
 import androidx.fragment.app.FragmentActivity;
 
 import com.google.android.material.appbar.CollapsingToolbarLayout;
@@ -40,8 +41,15 @@
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        super.setContentView(R.layout.collapsing_toolbar_base_layout);
-        mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
+        // TODO(b/181723278): Update the version check after SDK for S is finalized
+        // The collapsing toolbar is only supported if the android platform version is S or higher.
+        // Otherwise the regular action bar will be shown.
+        if (BuildCompat.isAtLeastS()) {
+            super.setContentView(R.layout.collapsing_toolbar_base_layout);
+            mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
+        } else {
+            super.setContentView(R.layout.toolbar_base_layout);
+        }
 
         final Toolbar toolbar = findViewById(R.id.action_bar);
         setActionBar(toolbar);
@@ -90,6 +98,14 @@
         super.setTitle(titleId);
     }
 
+    @Override
+    public boolean onNavigateUp() {
+        if (!super.onNavigateUp()) {
+            finish();
+        }
+        return true;
+    }
+
     /**
      * Returns an instance of collapsing toolbar.
      */
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 79fbcc3..9624119 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1059,7 +1059,14 @@
     <!-- Title for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
     <string name="accessibility_display_daltonizer_preference_title">Color correction</string>
     <!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
-    <string name="accessibility_display_daltonizer_preference_subtitle"><![CDATA[Color correction allows you to adjust how colors are displayed on your device]]></string>
+    <string name="accessibility_display_daltonizer_preference_subtitle">
+        <![CDATA[
+        Adjust how colors display on your device. This can be helpful when you want to:<br/><br/>
+        <ol>
+            <li> See colors more accurately</li>
+            <li> Remove colors to help you focus</li>
+        </ol>
+        ]]></string>
     <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
     <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
 
@@ -1295,6 +1302,8 @@
 
     <!-- Name of the phone device. [CHAR LIMIT=30] -->
     <string name="media_transfer_this_device_name">Phone speaker</string>
+    <!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
+    <string name="media_transfer_this_phone">This phone</string>
 
     <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
     <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
index 228de03..35499c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
@@ -80,7 +80,8 @@
      * Fills a list of applications which queried location recently within specified time.
      * Apps are sorted by recency. Apps with more recent location accesses are in the front.
      */
-    public List<Access> getAppList() {
+    @VisibleForTesting
+    List<Access> getAppList(boolean showSystemApps) {
         // Retrieve a location usage list from AppOps
         PackageManager pm = mContext.getPackageManager();
         AppOpsManager aoManager =
@@ -108,22 +109,26 @@
 
             // Don't show apps that do not have user sensitive location permissions
             boolean showApp = true;
-            for (int op : LOCATION_OPS) {
-                final String permission = AppOpsManager.opToPermission(op);
-                final int permissionFlags = pm.getPermissionFlags(permission, packageName, user);
-                if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
-                        PermissionChecker.PID_UNKNOWN, uid, packageName)
-                                == PermissionChecker.PERMISSION_GRANTED) {
-                    if ((permissionFlags
-                            & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) == 0) {
-                        showApp = false;
-                        break;
-                    }
-                } else {
-                    if ((permissionFlags
-                            & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0) {
-                        showApp = false;
-                        break;
+            if (!showSystemApps) {
+                for (int op : LOCATION_OPS) {
+                    final String permission = AppOpsManager.opToPermission(op);
+                    final int permissionFlags = pm.getPermissionFlags(permission, packageName,
+                            user);
+                    if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
+                            PermissionChecker.PID_UNKNOWN, uid, packageName)
+                            == PermissionChecker.PERMISSION_GRANTED) {
+                        if ((permissionFlags
+                                & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)
+                                == 0) {
+                            showApp = false;
+                            break;
+                        }
+                    } else {
+                        if ((permissionFlags
+                                & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0) {
+                            showApp = false;
+                            break;
+                        }
                     }
                 }
             }
@@ -137,8 +142,15 @@
         return accesses;
     }
 
-    public List<Access> getAppListSorted() {
-        List<Access> accesses = getAppList();
+
+    /**
+     * Gets a list of apps that accessed location recently, sorting by recency.
+     *
+     * @param showSystemApps whether includes system apps in the list.
+     * @return the list of apps that recently accessed location.
+     */
+    public List<Access> getAppListSorted(boolean showSystemApps) {
+        List<Access> accesses = getAppList(showSystemApps);
         // Sort the list of Access by recency. Most recent accesses first.
         Collections.sort(accesses, Collections.reverseOrder(new Comparator<Access>() {
             @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
index ecd4066..f9584a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -38,6 +38,7 @@
 import android.os.UserManager;
 import android.provider.ContactsContract.DisplayPhoto;
 import android.provider.MediaStore;
+import android.util.EventLog;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
@@ -126,6 +127,14 @@
         }
         final Uri pictureUri = data != null && data.getData() != null
                 ? data.getData() : mTakePictureUri;
+
+        // Check if the result is a content uri
+        if (!ContentResolver.SCHEME_CONTENT.equals(pictureUri.getScheme())) {
+            Log.e(TAG, "Invalid pictureUri scheme: " + pictureUri.getScheme());
+            EventLog.writeEvent(0x534e4554, "172939189", -1, pictureUri.getPath());
+            return false;
+        }
+
         switch (requestCode) {
             case REQUEST_CODE_CROP_PHOTO:
                 onPhotoCropped(pictureUri);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index 245b7843..16d73a3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -86,7 +86,7 @@
     @Test
     @Ignore
     public void testGetAppList_shouldFilterRecentAccesses() {
-        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList(false);
         // Only two of the apps have requested location within 15 min.
         assertThat(requests).hasSize(2);
         // Make sure apps are ordered by recency
@@ -115,7 +115,7 @@
         mockTestApplicationInfos(
                 Process.SYSTEM_UID, RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME);
 
-        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList(true);
         // Android OS shouldn't show up in the list of apps.
         assertThat(requests).hasSize(2);
         // Make sure apps are ordered by recency
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1ce738e..a0b9528 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -551,9 +551,6 @@
                 Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
                 GlobalSettingsProto.Development.FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
         dumpSetting(s, p,
-                Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
-                GlobalSettingsProto.Development.ENABLE_SIZECOMPAT_FREEFORM);
-        dumpSetting(s, p,
                 Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
                 GlobalSettingsProto.Development.ENABLE_NON_RESIZABLE_MULTI_WINDOW);
         p.end(developmentToken);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 303e5bb..4dc6d14 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -227,7 +227,6 @@
                     Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
                     Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
                     Settings.Global.DEVELOPMENT_FORCE_RTL,
-                    Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
                     Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
                     Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
                     Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 71e0910..1393116 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -164,6 +164,7 @@
     <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
     <uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
     <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
+    <uses-permission android:name="android.permission.MANAGE_UI_TRANSLATION" />
     <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SET_TIME" />
diff --git a/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml b/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml
index 6f91d77..edfc0ab 100644
--- a/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml
+++ b/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml
@@ -20,6 +20,7 @@
      Make the visibility to "gone" to prevent failures.
  -->
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/add_new_sound_text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:minHeight="?android:attr/listPreferredItemHeightSmall"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 044216e..b6d942a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -338,6 +338,7 @@
         <activity android:name=".screenshot.LongScreenshotActivity"
                   android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
                   android:process=":screenshot"
+                  android:exported="false"
                   android:finishOnTaskLaunch="true" />
 
         <activity android:name=".screenrecord.ScreenRecordDialog"
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 60994d8..ee8d023 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -144,10 +144,6 @@
 
 Delegates SysUI events to WM Shell controllers.
 
-### [com.android.systemui.people.widget.PeopleSpaceWidgetEnabler](/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java)
-
-Enables People Space widgets.
-
 ---
 
  * [Plugins](/packages/SystemUI/docs/plugins.md)
diff --git a/packages/SystemUI/docs/media-controls-pipeline.png b/packages/SystemUI/docs/media-controls-pipeline.png
new file mode 100644
index 0000000..e7408ad
--- /dev/null
+++ b/packages/SystemUI/docs/media-controls-pipeline.png
Binary files differ
diff --git a/packages/SystemUI/docs/media-controls.md b/packages/SystemUI/docs/media-controls.md
new file mode 100644
index 0000000..579f453
--- /dev/null
+++ b/packages/SystemUI/docs/media-controls.md
@@ -0,0 +1,94 @@
+# SysUI Media Controls Pipeline
+
+[TOC]
+
+## Purpose
+
+Describe how events flow through the media controls pipeline, and provide a high level overview of what the different components do.
+
+## Pipeline Diagram
+
+![media controls pipeline](media-controls-pipeline.png)
+
+* Orange: External inputs
+* Blue: Internal listeners; all except `MediaDataManager` and `ResumeMediaBrowser` implement [`MediaDataManager.Listener`](/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt#711) and receive `onMediaDataLoaded` and `onMediaDataRemoved` events
+
+## Classes
+
+Files under [`systemui/media/`](/packages/SystemUI/src/com/android/systemui/media/):
+
+* UI
+   * `dialog/`
+      * Output switcher dialog (maintained by Settings team)
+   * IlluminationDrawable.kt
+   * LightSourceDrawable.kt
+      * These create the glow animation when you tap on a button (see [`qs_media_light_source`](/packages/SystemUI/res/drawable/qs_media_light_source.xml)). Should be reusable in other layouts.
+   * Carousel:
+      * MediaCarouselController.kt
+         * Keeps the carousel view up to date and handles state changes (e.g. expansion)
+         * Handles settings gear and page indicator
+      * MediaCarouselScrollHandler.kt
+         * Handles scrolling between players in the carousel
+      * MediaScrollView.kt
+         * Scrollview used in the carousel layout, has some custom measurement code
+   * Individual players:
+      * KeyguardMediaController.kt
+         * Lockscreen media controls have a special wrapper in order to work with the existing lockscreen notification layout
+      * MediaControlPanel.java
+         * Main class for media control UI
+      * SeekBarObserver.kt
+         * Updates seekbar state
+      * SeekBarViewModel.kt
+         * Implements its own `computePosition()` for the seekbar (to avoid continually polling the `PlaybackState`, which involves binder calls)
+         * Does some touch falsing (ignore flings, require drags to start near the thumb - otherwise users would often accidentally trigger the seekbar when they meant to move the carousel or shade)
+      * PlayerViewHolder.kt
+         * Holds references to the UI elements in the panel
+* Animation support:
+   * MediaHierarchyManager.kt
+      * Responsible for placement of media view and animation between hosts
+   * MediaHost.kt
+      * Every location that a media player could be located needs a `MediaHost`
+      * Tracks configuration (if it should show inactive media, needs falsing, etc.)
+   * MediaHostStatesManager.kt
+      * Manages the various media host states and coordinates heights between different players
+      * Has the most up to date state for any location
+   * MediaViewController.kt
+      * Controls a single instance of a media player, keeps the media view states up to date
+* Backend
+   * MediaData.kt
+      * Holds all the media data (track info, active/resume state, etc.)
+   * MediaDataCombineLatest.kt
+      * Combines update events from `MediaDataManager` and `MediaDeviceManager`, so that downstream listeners will have device info
+   * MediaDataFilter.kt
+      * Filters media data based on the current user
+      * Exit point for the pipeline: "external listeners" (currently `MediaHost` and `MediaCarouselController`), while they should be added via `MediaDataManager.addListener()`, will actually be listening to this output
+   * MediaDataManager.kt
+      * Entry point for the pipeline; initializes listener connections and assigns external listeners to the correct exit point
+      * Converts media notifications and resumable media info into `MediaData`
+   * MediaDeviceManager.kt
+      * Handles device updates
+   * MediaFeatureFlag.kt
+      * Utility to check whether media controls are enabled
+   * MediaSessionBasedFilter.kt
+      * Filters media events based on media session. This prevents duplicate controls in situations like casting where we might get both a local and remote object for the same media session.
+   * MediaTimeoutListener.kt
+      * Listens to `PlaybackState` and marks controls inactive after the media has been paused/stopped for 10 minutes (value can be adjusted locally with `adb shell setprop debug.sysui.media_timeout [ms]`)
+   * MediaResumeListener.kt
+      * Listens for new media data and attempts to find a valid `MediaBrowserService` for the app. If successful, sends the information back to the `MediaDataManager`
+      * Saves up to 5 valid `MediaBrowserService` components found this way, and queries them for recent media on boot or user change
+      * Note: the user can disable this feature completely (or block certain apps from being resumable) in [Settings](https://source.corp.google.com/android/packages/apps/Settings/src/com/android/settings/sound/ResumableMediaAppsController.java), in which case this listener will do nothing (or ignore updates from the blocked apps).
+   * ResumeMediaBrowser.java
+      * Connects to an app's [`MediaBrowser`](https://developer.android.com/reference/android/media/browse/MediaBrowser) to determine whether SystemUI is able to connect and find a recent [`MediaItem`](https://developer.android.com/reference/android/media/browse/MediaBrowser.MediaItem)
+* Factory classes (for unit testing):
+   * LocalMediaManagerFactory.kt
+   * MediaBrowserFactory.java
+   * MediaControllerFactory.java
+   * ResumeMediaBrowserFactory.java
+
+## Miscellaneous
+
+Other useful documents:
+
+* [go/sysui-media-resumption-requirements](https://goto.google.com/sysui-media-resumption-requirements) - Internal documentation for app developers about how to work with media resumption
+* [Playing nicely with media controls](https://android-developers.googleblog.com/2020/08/playing-nicely-with-media-controls.html) - blog post on the Android 11 updates
+* [Media Controls developer guide](https://developer.android.com/guide/topics/media/media-controls)
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
index 7986809..71cdaf5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
@@ -24,7 +24,7 @@
     <include
         style="@style/BouncerSecurityContainer"
         layout="@layout/keyguard_host_view"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content" />
 </FrameLayout>
 
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
index 04e645b..1e142ea 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
@@ -41,13 +41,14 @@
         android:layout_gravity="center">
         <com.android.keyguard.KeyguardSecurityViewFlipper
             android:id="@+id/view_flipper"
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:clipChildren="false"
             android:clipToPadding="false"
             android:paddingTop="@dimen/keyguard_security_view_top_margin"
             android:paddingStart="@dimen/keyguard_security_view_lateral_margin"
             android:paddingEnd="@dimen/keyguard_security_view_lateral_margin"
+            android:layout_gravity="center"
             android:gravity="center">
         </com.android.keyguard.KeyguardSecurityViewFlipper>
     </com.android.keyguard.KeyguardSecurityContainer>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
similarity index 73%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
index 380dd85..e09bf7e 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
@@ -14,8 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+
+<resources>
+    <bool name="can_use_one_handed_bouncer">true</bool>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml
index 8d9d6ee..6176f7c 100644
--- a/packages/SystemUI/res-keyguard/values/config.xml
+++ b/packages/SystemUI/res-keyguard/values/config.xml
@@ -22,4 +22,5 @@
 
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
+    <bool name="can_use_one_handed_bouncer">false</bool>
 </resources>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index ee86ae2..c0668db 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -38,8 +38,8 @@
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhd etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra iş profili silinəcək və bütün profil datası ləğv ediləcək."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 187ae58..cf9de5e 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -85,10 +85,10 @@
         android:tint="?attr/wallpaperTextColor" />
 
     <ImageView
-        android:id="@+id/alt_left_button"
+        android:id="@+id/wallet_button"
         android:layout_height="@dimen/keyguard_affordance_height"
         android:layout_width="@dimen/keyguard_affordance_width"
-        android:layout_gravity="bottom|start"
+        android:layout_gravity="bottom|end"
         android:scaleType="center"
         android:tint="?attr/wallpaperTextColor"
         android:layout_marginStart="24dp"
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index e2f3e2a..7ba28a8 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -76,7 +76,6 @@
         android:layout_height="wrap_content"
         android:layout_marginBottom="42dp"
         android:layout_marginHorizontal="48dp"
-        android:adjustViewBounds="true"
         app:layout_constrainedHeight="true"
         app:layout_constrainedWidth="true"
         app:layout_constraintTop_toBottomOf="@id/guideline"
@@ -110,6 +109,7 @@
         android:visibility="invisible"
         android:layout_width="200dp"
         android:layout_height="200dp"
+        android:elevation="2dp"
         app:layout_constraintTop_toBottomOf="@id/guideline"
         app:layout_constraintLeft_toLeftOf="parent"
         app:handleThickness="@dimen/screenshot_crop_handle_thickness"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 13572fa..db712e4 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -17,6 +17,7 @@
 <com.android.systemui.util.NeverExactlyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:minHeight="48dp"
     android:clickable="true"
     android:paddingBottom="@dimen/qs_tile_padding_top"
     android:paddingTop="@dimen/qs_tile_padding_top"
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml b/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
new file mode 100644
index 0000000..9b5752d
--- /dev/null
+++ b/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<com.android.systemui.biometrics.UdfpsAnimationViewEnroll
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/udfps_animation_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!-- Enrollment progress bar-->
+    <com.android.systemui.biometrics.UdfpsProgressBar
+        android:id="@+id/progress_bar"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:max="100"
+        android:padding="@dimen/udfps_enroll_progress_thickness"
+        android:progress="0"
+        android:layout_gravity="center"
+        android:visibility="gone"/>
+
+</com.android.systemui.biometrics.UdfpsAnimationViewEnroll>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
similarity index 83%
rename from packages/SystemUI/res/layout/udfps_animation_view.xml
rename to packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
index 380dd85..f32faa0 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
@@ -14,8 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
+<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+    android:layout_height="match_parent">
+</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
similarity index 83%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
index 380dd85..644d1ada 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
@@ -14,8 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
+<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+    android:layout_height="match_parent">
+</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index 6ae306e..e24c9e9 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -22,15 +22,10 @@
     android:layout_height="match_parent"
     systemui:sensorTouchAreaCoefficient="0.5">
 
-    <!-- Enrollment progress bar-->
-    <com.android.systemui.biometrics.UdfpsProgressBar
-        android:id="@+id/progress_bar"
+    <com.android.systemui.biometrics.UdfpsSurfaceView
+        android:id="@+id/hbm_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:max="100"
-        android:padding="@dimen/udfps_enroll_progress_thickness"
-        android:progress="0"
-        android:layout_gravity="center"
-        android:visibility="gone"/>
+        android:visibility="invisible"/>
 
 </com.android.systemui.biometrics.UdfpsView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 68c7467..c3a62b0 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot sonsopkoms"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Verminder helderheid"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is gedeaktiveer"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is geaktiveer"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Hierdie toestel behoort aan <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swiep vanaf ikoon vir foon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swiep vanaf ikoon vir stembystand"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swiep vanaf ikoon vir kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om op vibreer te stel."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om te demp."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"demp"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ontdemp"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreer"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Voeg by"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Voorgestel deur <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontroles opgedateer"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Toestel is gesluit"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN bevat letters of simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifieer <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Verkeerde PIN"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7618af8..0c0487d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ጸሐይ እስክትወጣ ድረስ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ላይ ይበራል"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"እስከ <xliff:g id="TIME">%s</xliff:g> ድረስ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ብሩህነትን ይቀንሱ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"ኤንኤፍሲ"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"ኤንኤፍሲ ተሰናክሏል"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"ኤንኤፍሲ ነቅቷል"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ይህ መሳሪያ ንብረትነቱ የ<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ነው"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ለስልክ ከአዶ ላይ ጠረግ ያድርጉ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ለድምጽ ረዳት ከአዶ ጠረግ ያድርጉ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ለካሜራ ከአዶ ላይ ጠረግ ያድርጉ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ።"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ።"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ድምጸ-ከል አድርግ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ድምጸ-ከልን አንሳ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ንዘር"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"አክል"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"በ<xliff:g id="APP">%s</xliff:g> የተጠቆመ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"መቆጣጠሪያዎች ተዘምነዋል"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"መሣሪያ ተቆልፏል"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ፒን ፊደሎችን ወይም ምልክቶችን ይይዛል"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> አረጋግጥ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"የተሳሳተ ፒን"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 67622c7..ae8df90 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -420,7 +420,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"حتى شروق الشمس"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"تفعيل الوضع في <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"حتى <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"تقليل السطوع"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"تم إيقاف الاتصال القريب المدى"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"تم تفعيل الاتصال القريب المدى"</string>
@@ -454,6 +455,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏افتح قفل الشاشة لاستخدام تقنية NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"هذا الجهاز يخص <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"يمكنك التمرير سريعًا من الرمز لتشغيل الهاتف"</string>
     <string name="voice_hint" msgid="7476017460191291417">"يمكنك التمرير سريعًا من الرمز لتشغيل المساعد الصوتي"</string>
     <string name="camera_hint" msgid="4519495795000658637">"يمكنك التمرير سريعًا من الرمز لتشغيل الكاميرا"</string>
@@ -637,6 +640,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. انقر للتعيين على الاهتزاز."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. انقر لكتم الصوت."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"كتم الصوت"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"إعادة الصوت"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"اهتزاز"</string>
@@ -1062,6 +1067,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"إضافة"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"اقتراح من <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"تم تعديل عناصر التحكّم."</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"الجهاز مُقفل."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"يشتمل رقم التعريف الشخصي على أحرف أو رموز."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"إثبات ملكية <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"رقم تعريف شخصي خاطئ"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b1b28ad..1f92570 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূৰ্যোদয়লৈকে"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ত অন কৰক"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পৰ্যন্ত"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"উজ্জ্বলতা কমাওক"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম হৈ আছে"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ৰ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ফ\'নৰ বাবে আইকনৰপৰা ছোৱাইপ কৰক"</string>
     <string name="voice_hint" msgid="7476017460191291417">"কণ্ঠধ্বনিৰে সহায়ৰ বাবে আইকনৰ পৰা ছোৱাইপ কৰক"</string>
     <string name="camera_hint" msgid="4519495795000658637">"কেমেৰা খুলিবলৈ আইকনৰপৰা ছোৱাইপ কৰক"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট কৰিবলৈ টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। কম্পন অৱস্থাত ছেট কৰিবলৈ টিপক।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট কৰক"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট কৰক"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"কম্পন কৰক"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ দিয়ক"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>এ পৰামৰ্শ হিচাপে আগবঢ়োৱা"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"নিয়ন্ত্ৰণসমূহ আপডে\'ট কৰা হৈছে"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইচ লক হৈ আছে"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিনত বৰ্ণ অথবা প্ৰতীকসমূহ থাকে"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> সত্যাপন কৰক"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ভুল পিন"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index fed444b..e813a90 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Şəfəq vaxtına qədər"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bu vaxt aktiv olur: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bu vaxtadək: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Parlaqlığı Azaldın"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC deaktiv edilib"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC aktiv edilib"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> təşkilatına məxsusdur"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefon üçün ikonadan sürüşdürün"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Səs yardımçısı üçün ikonadan sürüşdürün"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kamera üçün ikonadan sürüşdürün"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Vibrasiyanı ayarlamaq üçün klikləyin."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Səssiz etmək üçün klikləyin."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"susdurun"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"səssiz rejimdən çıxarın"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrasiya"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Əlavə edin"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tərəfindən təklif edilib"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Nizamlayıcılar güncəlləndi"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilidlənib"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN hərflər və ya simvollar ehtiva edir"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Yanlış PIN"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ded8fa5..27d4b18 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanji osvetljenost"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Prevucite od ikone za telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Prevucite od ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone za kameru"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste podesili na vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibracija"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifikujte: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 18756f8..ab1cc69 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Да ўсходу сонца"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Уключана ў <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Да <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Паменшыць яркасць"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC адключаны"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC уключаны"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Гэта прылада належыць арганізацыі \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Тэлефон: правядзіце пальцам ад значка"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камера: правядзіце пальцам ад значка"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дакраніцеся, каб уключыць вібрацыю."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дакраніцеся, каб адключыць гук"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"выключыць гук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"уключыць гук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вібрыраваць"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Дадаць"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Прапанавана праграмай \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы кіравання абноўлены"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Прылада блакіравана"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код складаецца з літар або знакаў"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Спраўдзіце прыладу \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Няправільны PIN-код"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e1efd3b..6716e15 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрев"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ще се включи в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Намаляване на яркостта"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"КБП е деактивирана"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"КБП е активирана"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Това устройство принадлежи на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Плъзнете с пръст от иконата, за да използвате телефона"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Прекарайте пръст от иконата, за да получите гласова помощ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Плъзнете с пръст от иконата, за да включите камерата"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Докоснете, за да зададете вибриране."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Докоснете, за да заглушите звука."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"спиране"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"пускане"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибриране"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавяне"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено от <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите са актуализирани"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"У-вото е заключено"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН кодът съдържа букви или символи"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Потвърждаване на <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Грешен ПИН код"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 12f5345..ee639d6 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"স্ক্রিনশট স্ক্রল করুন"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্রিনশট বাতিল করুন"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"স্ক্রিনশটের একদম উপরের দিকে"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"স্ক্রিনশটের একদম নিচের দিকে"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"স্ক্রিন রেকর্ডার"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূর্যোদয় পর্যন্ত"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-এ চালু হবে"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পর্যন্ত"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"উজ্জ্বলতা কমান"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC অক্ষম করা আছে"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম করা আছে"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-এর"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ফোনের জন্য আইকন থেকে সোয়াইপ করুন"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ভয়েস সহায়তার জন্য আইকন থেকে সোয়াইপ করুন"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ক্যামেরার জন্য আইকন থেকে সোয়াইপ করুন"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"আপনার প্রতিষ্ঠান আপনার অফিস প্রোফাইলে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করেছে। আপনার নিরাপদ নেটওয়ার্ক ট্রাফিকে নজর রাখা হতে পারে বা তাতে পরিবর্তন করা হতে পারে।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"এই ডিভাইসে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করা আছে। আপনার নিরাপদ নেটওয়ার্ক ট্রাফিকে নজর রাখা হতে পারে বা তাতে পরিবর্তন করা হতে পারে।"</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিকের উপরে নজর রাখে।"</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"আপনার অ্যাডমিন নেটওয়ার্ক লগ করা চালু করেছেন যা আপনার অফিস প্রোফাইলে ট্রাফিক মনিটর করে তবে ব্যক্তিগত প্রোফাইলে করে না।"</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত রয়েছেন, যা আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটির উপর নজর রাখতে পারে।"</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"আপনি <xliff:g id="VPN_APP_0">%1$s</xliff:g> এবং <xliff:g id="VPN_APP_1">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেগুলি আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটির উপর নজর রাখতে পারে।"</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"আপনার কর্মস্থলের প্রোফাইল <xliff:g id="VPN_APP">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছে, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে।"</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট করতে ট্যাপ করুন।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট করুন"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট করুন"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ভাইব্রেট করান"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ করুন"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> সাজেস্ট করেছে"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"কন্ট্রোল আপডেট করা হয়েছে"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইস লক করা আছে"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিন-এ অক্ষর বা চিহ্ন রয়েছে"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> যাচাই করুন"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ভুল পিন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 7463233..01a55d3 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svitanja"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanji osvjetljenje"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Prevucite preko ikone da otvorite telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Prevucite preko ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone da otvorite kameru"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da postavite vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da isključite zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 524bb62..5d8ccbc 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fins a l\'alba"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activat a les <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fins a les <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducció de la brillantor"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"L\'NFC està desactivada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"L\'NFC està activada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Aquest dispositiu pertany a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Llisca des de la icona per obrir el telèfon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Llisca des de la icona per obrir l\'assistent de veu"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Llisca des de la icona per obrir la càmera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca per activar la vibració."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca per silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"deixar de silenciar"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Afegeix"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggerit per <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"S\'han actualitzat els controls"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositiu bloquejat"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN conté lletres o símbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecte"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 47a673d..024b836 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svítání"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapnout v <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Snížit jas"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zařízení patří organizaci <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefon otevřete přejetím prstem od ikony"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Hlasovou asistenci otevřete přejetím prstem od ikony"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otevřete přejetím prstem od ikony"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrace."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnout zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrovat"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Přidat"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Návrh z aplikace <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládací prvky aktualizovány"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Zařízení uzamčeno"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmena nebo symboly"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Ověření zařízení <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Chybný PIN"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index e12b91c..b1a7a5a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Indtil solopgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Tænd kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Indtil kl. <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducer lysstyrken"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er deaktiveret"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er aktiveret"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enhed tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Stryg fra telefonikonet"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Stryg fra mikrofonikonet"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Stryg fra kameraikonet"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryk for at aktivere vibration."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryk for at slå lyden fra."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå lyden til"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tilføj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Foreslået af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Betjeningselementerne er opdateret"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Enheden er låst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden indeholder bogstaver eller symboler"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Bekræft <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Forkert pinkode"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6a69ed2..88dd62d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"Screenshot scrollen"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"Oberer Rand"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Unterer Rand"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Bis Sonnenaufgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"An um <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bis <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Helligkeit verringern"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ist deaktiviert"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ist aktiviert"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Zum Öffnen des Telefons vom Symbol wegwischen"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Zum Öffnen des Sprachassistenten vom Symbol wegwischen"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Zum Öffnen der Kamera vom Symbol wegwischen"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Deine Organisation hat ein Zertifikat einer Zertifizierungsstelle in deinem Arbeitsprofil installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Auf dem Gerät ist das Zertifikat einer Zertifizierungsstelle installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit wird der Netzwerkverkehr auf deinem Gerät überwacht."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit werden die Zugriffe in deinem Arbeitsprofil erfasst, jedoch nicht in deinem privaten Profil."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Du bist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden. Die App kann deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Du bist mit <xliff:g id="VPN_APP_0">%1$s</xliff:g> und <xliff:g id="VPN_APP_1">%2$s</xliff:g> verbunden. Die Apps können deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Dein Arbeitsprofil ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden, die deine Netzwerkaktivitäten wie E-Mails, Apps und Websites überwachen kann."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Zum Aktivieren der Vibration tippen."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Zum Stummschalten tippen."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stummschalten"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"Stummschaltung aufheben"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrieren"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Hinzufügen"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Vorgeschlagen von <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Gerätekarten aktualisiert"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Gerät gesperrt"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Die PIN enthält Buchstaben oder Symbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> bestätigen"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Falsche PIN"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5bed0e5..2133025 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Μέχρι την ανατολή"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ενεργοποίηση στις <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Έως <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Μείωση φωτεινότητας"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Το NFC είναι απενεργοποιημένο"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Το NFC είναι ενεργοποιημένο"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Αυτή η συσκευή ανήκει στον οργανισμό <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Σύρετε προς τα έξω για τηλέφωνο"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Σύρετε προς τα έξω για voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Σύρετε προς τα έξω για κάμερα"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Πατήστε για να ενεργοποιήσετε τη δόνηση."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Πατήστε για σίγαση."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"δόνηση"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Προσθήκη"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Προτείνεται από <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ενημέρωση στοιχείων ελέγχου"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Η συσκευή κλειδώθηκε"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Το PIN περιέχει γράμματα ή σύμβολα"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Επαλήθευση <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Λάθος PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 5df29337..403fdee 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 46c09f6..a665fb1 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎Until sunrise‎‏‎‎‏‎"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎On at ‎‏‎‎‏‏‎<xliff:g id="TIME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎Until ‎‏‎‎‏‏‎<xliff:g id="TIME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎Reduce Brightness‎‏‎‎‏‎"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎Reduce brightness‎‏‎‎‏‎"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎NFC‎‏‎‎‏‎"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎NFC is disabled‎‏‎‎‏‎"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎NFC is enabled‎‏‎‎‏‎"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎Unlock to use NFC‎‏‎‎‏‎"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎This device belongs to your organization‎‏‎‎‏‎"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎This device belongs to ‎‏‎‎‏‏‎<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎Swipe from icon for phone‎‏‎‎‏‎"</string>
     <string name="voice_hint" msgid="7476017460191291417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎Swipe from icon for voice assist‎‏‎‎‏‎"</string>
     <string name="camera_hint" msgid="4519495795000658637">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎Swipe from icon for camera‎‏‎‎‏‎"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎%1$s. Tap to mute. Accessibility services may be muted.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎%1$s. Tap to set to vibrate.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎%1$s. Tap to mute.‎‏‎‎‏‎"</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‎‎Tap to change ringer mode‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎mute‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎unmute‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎vibrate‎‏‎‎‏‎"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎Add‎‏‎‎‏‎"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎Suggested by ‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎Controls updated‎‏‎‎‏‎"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎Device locked‎‏‎‎‏‎"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎PIN contains letters or symbols‎‏‎‎‏‎"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎Verify ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎Wrong PIN‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e1ad516..c97194f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir el brillo"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"La tecnología NFC está inhabilitada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"La tecnología NFC está habilitada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Desliza el dedo para desbloquear el teléfono."</string>
     <string name="voice_hint" msgid="7476017460191291417">"Desliza el dedo desde el ícono para abrir asistente de voz."</string>
     <string name="camera_hint" msgid="4519495795000658637">"Desliza el dedo para acceder a la cámara."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Presiona para establecer el modo vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Presiona para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Agregar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispos. bloqueado"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c4b8b24..4c5ef0b 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta las <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir brillo"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"El NFC está desactivado"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"El NFC está activado"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Desliza desde el icono para abrir el teléfono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Desliza desde el icono para abrir asistente de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Desliza desde el icono para abrir la cámara"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para activar la vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Añadir"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloqueado"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5402b61..65c5930 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuni päikesetõusuni"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Sisse kell <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuni <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Ereduse vähendamine"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on keelatud"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on lubatud"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Selle seadme omanik on <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefoni kasutamiseks pühkige ikoonilt eemale"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Häälabi kasutamiseks pühkige ikoonilt eemale"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kaamera kasutamiseks pühkige ikoonilt eemale"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Puudutage vibreerimise määramiseks."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Puudutage vaigistamiseks."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vaigistamine"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vaigistuse tühistamine"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreerimine"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisa"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Soovitas <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Juhtelemente värskendati"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Seade on lukustatud"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-kood sisaldab tähti või sümboleid"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Kinnitage <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Vale PIN-kood"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 510e7f9..9cebde1 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Egunsentira arte"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Desaktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Murriztu distira"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Desgaituta dago NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Gaituta dago NFC"</string>
@@ -443,9 +444,11 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Irekitzeko, ukitu berriro"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
-    <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokeatu NFC erabiltzeko"</string>
+    <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Gailu hau <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> erakundearena da"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Pasatu hatza ikonotik, telefonoa irekitzeko"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Pasatu hatza ikonotik, ahots-laguntza irekitzeko"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Pasatu hatza ikonotik, kamera irekitzeko"</string>
@@ -461,8 +464,8 @@
     <string name="keyguard_indication_charging_time_fast" msgid="7895986003578341126">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte)"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="245442950133408398">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
-    <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Aldatu erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string>
-    <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Uneko erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+    <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Aldatu erabiltzailea. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita daukana."</string>
+    <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Erakutsi profila"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzailea"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
@@ -478,7 +481,7 @@
     <string name="guest_notification_text" msgid="4202692942089571351">"Aplikazioak eta datuak ezabatzeko, kendu gonbidatua"</string>
     <string name="guest_notification_remove_action" msgid="4153019027696868099">"KENDU GONBIDATUA"</string>
     <string name="user_logout_notification_title" msgid="3644848998053832589">"Amaitu erabiltzailearen saioa"</string>
-    <string name="user_logout_notification_text" msgid="7441286737342997991">"Amaitu uneko erabiltzailearen saioa"</string>
+    <string name="user_logout_notification_text" msgid="7441286737342997991">"Amaitu erabiltzailearen saioa"</string>
     <string name="user_logout_notification_action" msgid="7974458760719361881">"AMAITU ERABILTZAILEAREN SAIOA"</string>
     <string name="user_add_user_title" msgid="4172327541504825032">"Beste erabiltzaile bat gehitu?"</string>
     <string name="user_add_user_message_short" msgid="2599370307878014791">"Erabiltzaile bat gehitzen duzunean, horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
@@ -544,7 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Erakundeak ziurtagiri-emaile bat instalatu dizu laneko profilean. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Ziurtagiri-emaile bat dago instalatuta gailuan. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake."</string>
-    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure laneko profileko trafikoa gainbegira dezake, baina ez zure profil pertsonalekoa."</string>
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratzaileak sarearen erregistroak aktibatu ditu; horrela, zure laneko profileko trafikoa gainbegira dezake, baina ez zure profil pertsonalekoa."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> eta <xliff:g id="VPN_APP_1">%2$s</xliff:g> aplikazioetara konektatuta zaude, eta haiek sareko jarduerak gainbegira ditzakete, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora dago konektatuta laneko profila, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Sakatu hau dardara ezartzeko."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sakatu hau audioa desaktibatzeko."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desaktibatu audioa"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktibatu audioa"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dardara"</string>
@@ -954,7 +959,7 @@
     <string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"Datu-konexioa desaktibatu nahi duzu?"</string>
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
-    <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Uneko operadorea"</string>
+    <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Zure operadorea"</string>
     <string name="touch_filtered_warning" msgid="8119511393338714836">"Aplikazio bat baimen-eskaera oztopatzen ari denez, ezarpenek ezin dute egiaztatu erantzuna."</string>
     <string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakusteko baimena eman nahi diozu <xliff:g id="APP_0">%1$s</xliff:g> aplikazioari?"</string>
     <string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Gehitu"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> aplikazioak iradoki du"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Eguneratu dira kontrolatzeko aukerak"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Gailua blokeatuta"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodeak hizkiak edo ikurrak ditu"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Egiaztatu <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN okerra"</string>
@@ -1049,8 +1055,8 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string>
-    <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu uneko saioa."</string>
-    <string name="controls_media_active_session" msgid="1984383994625845642">"Ezin da ezkutatu uneko saioa."</string>
+    <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu saioa."</string>
+    <string name="controls_media_active_session" msgid="1984383994625845642">"Ezin da ezkutatu saioa."</string>
     <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 72d7b50..04b14f1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"تا طلوع آفتاب"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ساعت <xliff:g id="TIME">%s</xliff:g> روشن می‌شود"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"تا<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"کاهش روشنایی"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"‏ارتباط میدان نزدیک (NFC)"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‏«ارتباط میدان نزدیک» (NFC) غیرفعال است"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏«ارتباط میدان نزدیک» (NFC) فعال است"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏برای استفاده از NFC، قفل را باز کنید"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"این دستگاه به <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> تعلق دارد"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"انگشتتان را از نماد تلفن تند بکشید"</string>
     <string name="voice_hint" msgid="7476017460191291417">"برای «دستیار صوتی»، تند بکشید"</string>
     <string name="camera_hint" msgid="4519495795000658637">"انگشتتان را از نماد دوربین تند بکشید"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری صامت شود."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. برای صامت کردن ضربه بزنید."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"صامت کردن"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"باصدا کردن"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"لرزش"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"افزودن"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"پیشنهاد <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"کنترل‌ها به‌روزرسانی شد"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"دستگاه قفل است"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"پین شامل حروف یا نماد است"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"تأیید <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"پین اشتباه است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 457d765..d08bfb5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -125,7 +125,7 @@
     <string name="use_ptp_button_title" msgid="7676427598943446826">"Käytä kamerana (PTP)"</string>
     <string name="installer_cd_button_title" msgid="5499998592841984743">"Asenna Android File Transfer -sovellus Macille"</string>
     <string name="accessibility_back" msgid="6530104400086152611">"Takaisin"</string>
-    <string name="accessibility_home" msgid="5430449841237966217">"Aloituspainike"</string>
+    <string name="accessibility_home" msgid="5430449841237966217">"Aloitus"</string>
     <string name="accessibility_menu" msgid="2701163794470513040">"Valikko"</string>
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"Esteettömyys"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"Näytön kääntäminen"</string>
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Auringonnousuun"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Päälle klo <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> asti"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Vähennä kirkkautta"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on poistettu käytöstä"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on käytössä"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> omistaa tämän laitteen"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Avaa puhelu pyyhkäisemällä."</string>
     <string name="voice_hint" msgid="7476017460191291417">"Avaa ääniapuri pyyhkäisemällä kuvakkeesta."</string>
     <string name="camera_hint" msgid="4519495795000658637">"Avaa kamera pyyhkäisemällä."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Siirry värinätilaan napauttamalla."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Mykistä napauttamalla."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mykistä"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"poista mykistys"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"värinä"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisää"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Ehdottaja: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Säätimet päivitetty"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Laite lukittu"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koodi sisältää kirjaimia tai symboleja"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Vahvista <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Väärä PIN-koodi"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3c4a9108..3d1ab93 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Réduire la luminosité"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Balayez à partir de l\'icône pour accéder au téléphone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Balayez à partir de l\'icône pour accéder à l\'assist. vocale"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Balayez à partir de l\'icône pour accéder à l\'appareil photo"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Touchez pour activer les vibrations."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Touchez pour couper le son."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"désactiver le son"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le NIP contient des lettres ou des symboles"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Vérifier <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"NIP incorrect"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 629cbba..c6d0674 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -238,7 +238,7 @@
     <skip />
     <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
-    <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
+    <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Réglages rapides"</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
     <string name="accessibility_desc_settings" msgid="6728577365389151969">"Paramètres"</string>
     <string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"Aperçu"</string>
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"À partir de <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Réduire la luminosité"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"La technologie NFC est activée"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Balayer pour téléphoner"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Balayer l\'écran depuis l\'icône pour l\'assistance vocale"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Balayer pour prendre une photo"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Appuyez pour mettre en mode vibreur."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Appuyez pour ignorer."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"couper le son"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"activer le vibreur"</string>
@@ -640,7 +645,7 @@
     <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="6235377891802910455">"Afficher le pourcentage intégré de la batterie"</string>
     <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Affichez le pourcentage correspondant au niveau de la batterie dans l\'icône de la barre d\'état lorsque l\'appareil n\'est pas en charge."</string>
-    <string name="quick_settings" msgid="6211774484997470203">"Configuration rapide"</string>
+    <string name="quick_settings" msgid="6211774484997470203">"Réglages rapides"</string>
     <string name="status_bar" msgid="4357390266055077437">"Barre d\'état"</string>
     <string name="overview" msgid="3522318590458536816">"Aperçu"</string>
     <string name="demo_mode" msgid="263484519766901593">"Mode de démonstration de l\'interface du système"</string>
@@ -650,13 +655,13 @@
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
-    <string name="add_tile" msgid="6239678623873086686">"Ajouter une tuile"</string>
-    <string name="broadcast_tile" msgid="5224010633596487481">"Tuile de diffusion"</string>
+    <string name="add_tile" msgid="6239678623873086686">"Ajouter un bloc"</string>
+    <string name="broadcast_tile" msgid="5224010633596487481">"Bloc de diffusion"</string>
     <string name="zen_alarm_warning_indef" msgid="5252866591716504287">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>, sauf si vous désactivez cette option avant."</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
     <string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuration rapide – <xliff:g id="TITLE">%s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Réglages rapides – <xliff:g id="TITLE">%s</xliff:g>"</string>
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Point d\'accès"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
@@ -669,8 +674,8 @@
     <string name="activity_not_found" msgid="8711661533828200293">"L\'application n\'est pas installée sur votre appareil."</string>
     <string name="clock_seconds" msgid="8709189470828542071">"Afficher les secondes sur l\'horloge"</string>
     <string name="clock_seconds_desc" msgid="2415312788902144817">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
-    <string name="qs_rearrange" msgid="484816665478662911">"Réorganiser la fenêtre de configuration rapide"</string>
-    <string name="show_brightness" msgid="6700267491672470007">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
+    <string name="qs_rearrange" msgid="484816665478662911">"Réorganiser les Réglages rapides"</string>
+    <string name="show_brightness" msgid="6700267491672470007">"Afficher la luminosité dans les Réglages rapides"</string>
     <string name="experimental" msgid="3549865454812314826">"Paramètres expérimentaux"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"Activer le Bluetooth ?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
@@ -878,20 +883,20 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Afficher les icônes de notification à faible priorité"</string>
     <string name="other" msgid="429768510980739978">"Autre"</string>
-    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer la carte"</string>
-    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ajouter la carte à la fin"</string>
-    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer la carte"</string>
-    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter une carte"</string>
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer le bloc"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ajouter le bloc à la fin"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer le bloc"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter un bloc"</string>
     <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Déplacer vers <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
-    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Carte ajoutée"</string>
-    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Carte supprimée"</string>
-    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur de configuration rapide."</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloc ajouté"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloc supprimé"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur Réglages rapides"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notification <xliff:g id="ID_1">%1$s</xliff:g> : <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ouvrir les paramètres."</string>
-    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Ouvrir la fenêtre de configuration rapide."</string>
-    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fermer la fenêtre de configuration rapide."</string>
+    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Ouvrir les Réglages rapides."</string>
+    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fermer les Réglages rapides."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Alarme définie."</string>
     <string name="accessibility_quick_settings_user" msgid="505821942882668619">"Connecté en tant que <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="691058178914184544">"Aucun accès à Internet"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggérée par <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le code contient des lettres ou des symboles"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Valider <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Code incorrect"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9383fb6..08841a2 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Ata o amencer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activarase ás: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Utilizarase ata as: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir brillo"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"A opción NFC está desactivada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"A opción NFC está activada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Pasa o dedo desde a icona para acceder ao teléfono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Pasa o dedo desde a icona para acceder ao asistente de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Pasa o dedo desde a icona para acceder á cámara"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para establecer a vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activar o son"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Engadir"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Control suxerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Actualizáronse os controis"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Disposit. bloqueado"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contén letras ou símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"O PIN é incorrecto"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index be62a29..867bc2f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"સ્ક્રીનશૉટ પર સ્ક્રોલ કરો"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"સ્ક્રીનશૉટની સૌથી ઉપરની બાજુની સીમા"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"સ્ક્રીનશૉટની સૌથી નીચેની બાજુની સીમા"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકૉર્ડર"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"સૂર્યોદય સુધી"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> વાગ્યે ચાલુ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> વાગ્યા સુધી"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"બ્રાઇટનેસ ઘટાડો"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC અક્ષમ કરેલ છે"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC સક્ષમ કરેલ છે"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ની માલિકીનું છે"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ફોન માટે આયકનમાંથી સ્વાઇપ કરો"</string>
     <string name="voice_hint" msgid="7476017460191291417">"વૉઇસ સહાય માટે આયકનમાંથી સ્વાઇપ કરો"</string>
     <string name="camera_hint" msgid="4519495795000658637">"કૅમેરા માટે આયકનમાંથી સ્વાઇપ કરો"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"તમારી સંસ્થાએ તમારી કાર્ય પ્રોફાઇલમાં પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કર્યું છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"આ ઉપકરણ પર પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કરેલ છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યું છે, જે તમારા ઉપકરણ પર નેટવર્ક ટ્રાફિકનું નિયમન કરે છે."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગ ઇન ચાલુ કર્યુ છે, જે તમારી વ્યક્તિગત પ્રોફાઇલમાં નહીં, પરંતુ ઑફિસની પ્રોફાઇલમાં ટ્રાફિકનું નિરીક્ષણ કરે છે."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"તમે <xliff:g id="VPN_APP_0">%1$s</xliff:g> અને <xliff:g id="VPN_APP_1">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. કંપન પર સેટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"મ્યૂટ કરો"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"અનમ્યૂટ કરો"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"વાઇબ્રેટ"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ઉમેરો"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> દ્વારા સૂચન કરેલા"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"નિયંત્રણ અપડેટ કર્યા"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ડિવાઇસ લૉક કરેલું છે"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"પિનમાં અક્ષરો અથવા પ્રતીકોનો સમાવેશ થાય છે"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ને ચકાસો"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ખોટો પિન"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b487689..a357ad2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -93,8 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉट को स्क्रोल करें"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट को खारिज करें"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉट की झलक"</string>
-    <string name="screenshot_top_boundary" msgid="1500569103321300856">"स्क्रीनशाॉट की ऊपर की सीमा"</string>
-    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"स्क्रीनशॉट की नीचे की सीमा"</string>
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"स्क्रीनशॉट को ऊपर से काटने की सीमा"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"स्क्रीनशॉट को नीचे से काटने की सीमा"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सुबह तक चालू रहेगी"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> पर चालू हाेगी"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> तक चालू रहेगी"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"स्क्रीन की चमक कम करें"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"एनएफ़सी"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC बंद है"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC चालू है"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"इस डिवाइस का मालिकाना हक <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> के पास है"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"फ़ोन के लिए आइकॉन से स्वाइप करें"</string>
     <string name="voice_hint" msgid="7476017460191291417">"\'आवाज़ से डिवाइस का इस्तेमाल\' आइकॉन से स्वाइप करें"</string>
     <string name="camera_hint" msgid="4519495795000658637">"कैमरे के लिए आइकॉन से स्वाइप करें"</string>
@@ -546,7 +549,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"आपके संगठन ने आपकी वर्क प्रोफ़ाइल में एक प्रमाणपत्र अनुमति इंस्टॉल की है. आपके सुरक्षित नेटवर्क ट्रैफ़िक की निगरानी या उसमें बदलाव किया जा सकता है."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"इस डिवाइस पर एक प्रमाणपत्र अनुमति इंस्टॉल की है. आपके सुरक्षित नेटवर्क ट्रैफ़िक की निगरानी या उसमें बदलाव किया जा सकता है."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"आपके व्यवस्थापक ने नेटवर्क लॉगिंग चालू किया है, जो आपके डिवाइस पर ट्रैफ़िक की निगरानी करता है."</string>
-    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"आपके एडमिन ने नेटवर्क लॉगिंग की सुविधा चालू कर दी है, जिससे आपकी वर्क प्रोफ़ाइल पर आने वाले ट्रैफ़िक की निगरानी की जाती है. हालांकि, इससे आपकी निजी प्रोफ़ाइल की निगरानी नहीं की जाती."</string>
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"आपके एडमिन ने नेटवर्क लॉगिंग की सुविधा चालू कर दी है. इससे आपकी वर्क प्रोफ़ाइल पर आने वाले ट्रैफ़िक की निगरानी की जाती है. हालांकि, इससे आपकी निजी प्रोफ़ाइल की निगरानी नहीं की जाती."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"आप <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकते हैं."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"आप <xliff:g id="VPN_APP_0">%1$s</xliff:g> और <xliff:g id="VPN_APP_1">%2$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकते हैं."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"आपकी वर्क प्रोफ़ाइल <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्ट है, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
@@ -627,6 +630,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. कंपन (वाइब्रेशन) पर सेट करने के लिए छूएं."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करने के लिए टैप करें."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करें"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्यूट करें"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"वाइब्रेशन की सुविधा चालू करें"</string>
@@ -1040,6 +1045,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"जोड़ें"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> से मिला सुझाव"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"कंट्रोल अपडेट किए गए"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"डिवाइस लॉक है"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिन में अक्षर या चिह्न शामिल होते हैं"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> की पुष्टि करें"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"गलत पिन"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 8f3d7c0..d8064ab 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanjenje svjetline"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Prijeđite prstom od ikone za telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Prijeđite prstom od ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Prijeđite prstom od ikone za fotoaparat"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste postavili na vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključivanje zvuka"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključivanje zvuka"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Preporuka s kanala <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4fda667..a736f88 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Napfelkeltéig"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Be: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Eddig: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Fényerő csökkentése"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Az NFC ki van kapcsolva"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Az NFC be van kapcsolva"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ez az eszköz a(z) <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tulajdonában van"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"A telefonhoz csúsztasson az ikonról"</string>
     <string name="voice_hint" msgid="7476017460191291417">"A hangsegéd eléréséhez csúsztassa ujját az ikonról"</string>
     <string name="camera_hint" msgid="4519495795000658637">"A fényképezőhöz csúsztasson az ikonról"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Koppintson a rezgés beállításához."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Koppintson a némításhoz."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"némítás"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"némítás feloldása"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rezgés"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Hozzáadás"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> javasolta"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Vezérlők frissítve"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Az eszköz zárolva van"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"A PIN-kód betűket vagy szimbólumokat tartalmaz"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ellenőrzése"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Helytelen PIN-kód"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index f0c1f21..40ddf54 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Մինչև լուսաբաց"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Կմիանա՝ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Մինչև <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Նվազեցնել պայծառությունը"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Պայծառության նվազեցում"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-ն անջատված է"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-ն միացված է"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպությանը"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Սահահարվածեք հեռախոսի պատկերակից"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Սահահարվածեք ձայնային հուշման պատկերակից"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Սահահարվածեք խցիկի պատկերակից"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s։ Հպեք՝ թրթռոցը միացնելու համար։"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s։ Հպեք՝ ձայնը անջատելու համար։"</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Հպեք՝ զանգակի ռեժիմը փոխելու համար"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"անջատել ձայնը"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"միացնել ձայնը"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"միացնել թրթռոցը"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ավելացնել"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Առաջարկվել է <xliff:g id="APP">%s</xliff:g> հավելվածի կողմից"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Կառավարման տարրերը թարմացվեցին"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Սարքը կողպված է"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN կոդը տառեր և նշաններ է պարունակում"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Ստուգել <xliff:g id="DEVICE">%s</xliff:g> սարքը"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN կոդը սխալ է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 71ff39c..e20dd51 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sampai pagi"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktif pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Sampai <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Kurangi Kecerahan"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dinonaktifkan"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC diaktifkan"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Perangkat ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Geser dari ikon untuk telepon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Geser dari ikon untuk bantuan suara"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Geser dari ikon untuk kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketuk untuk menyetel agar bergetar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketuk untuk menonaktifkan."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Tanpa suara"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktifkan"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambahkan"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Disarankan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrol diperbarui"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Perangkat terkunci"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN berisi huruf atau simbol"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifikasi <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN salah"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 482338a..0c99420 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til sólarupprásar"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Virkt kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Draga úr birtu"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Slökkt á NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Kveikt á NFC"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Þetta tæki tilheyrir <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Strjúktu frá tákninu fyrir síma"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Strjúktu frá tákninu fyrir raddaðstoð"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Strjúktu frá tákninu fyrir myndavél"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ýttu til að stilla á titring."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ýttu til að þagga."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"þagga"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"hætta að þagga"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titringur"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Bæta við"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Tillaga frá <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Stýringar uppfærðar"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Tækið er læst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN inniheldur bókstafi eða tákn"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Staðfesta <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Rangt PIN-númer"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0896d0c..527a695 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fino all\'alba"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Attivazione alle <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fino alle <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Riduci la luminosità"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC non attiva"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC attiva"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Scorri per accedere al telefono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Scorri dall\'icona per accedere a Voice Assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Scorri dall\'icona per accedere alla fotocamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tocca per attivare la vibrazione."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tocca per disattivare l\'audio."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"disattiva l\'audio"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Aggiungi"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggerito da <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlli aggiornati"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloccato"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Il PIN contiene lettere o simboli"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN errato"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e304dbe..9fc8b23 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"צילום מסך נגלל"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"הקצה העליון"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"הקצה התחתון"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
@@ -418,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"עד הזריחה"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"יתחיל בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"עד <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"הפחתה של עוצמת הבהירות"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‏NFC מושבת"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏NFC מופעל"</string>
@@ -452,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"המכשיר הזה שייך לארגון <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"החלק מהסמל כדי להפעיל את הטלפון"</string>
     <string name="voice_hint" msgid="7476017460191291417">"החלק מהסמל כדי להפעיל את המסייע הקולי"</string>
     <string name="camera_hint" msgid="4519495795000658637">"החלק מהסמל כדי להפעיל את המצלמה"</string>
@@ -552,8 +553,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"הארגון שלך התקין רשות אישורים בפרופיל העבודה. ניתן לעקוב אחר התנועה ברשת המאובטחת או לשנות אותה."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"במכשיר זה מותקנת רשות אישורים. ניתן לעקוב אחר התנועה ברשת המאובטחת או לשנות אותה."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"מנהל המערכת הפעיל את התכונה \'רישום התנועה ברשת\', שמנטרת את תנועת הנתונים במכשיר."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"מנהל המערכת הפעיל את תכונת רישום התנועה ברשת, שמנטרת את תנועת הנתונים בפרופיל העבודה, אבל לא בפרופיל האישי."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"אתה מחובר לאפליקציה <xliff:g id="VPN_APP">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"אתה מחובר לאפליקציות <xliff:g id="VPN_APP_0">%1$s</xliff:g> ו-<xliff:g id="VPN_APP_1">%2$s</xliff:g>, שיכולות לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"פרופיל העבודה שלך מחובר לאפליקציה <xliff:g id="VPN_APP">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
@@ -634,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. הקש כדי להעביר למצב רטט."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. הקש כדי להשתיק."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"רטט"</string>
@@ -1053,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"הוספה"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"הוצע על-ידי <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"הפקדים עודכנו"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"המכשיר נעול"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"קוד האימות מכיל אותיות או סמלים"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"אימות <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"קוד גישה שגוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 05b1f76..1b18b5c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"日の出まで"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>にオン"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>まで"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"明るさを下げる"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC は無効です"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC は有効です"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"これは <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> が所有するデバイスです"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"右にスワイプして通話"</string>
     <string name="voice_hint" msgid="7476017460191291417">"アイコンからスワイプして音声アシストを起動"</string>
     <string name="camera_hint" msgid="4519495795000658637">"左にスワイプしてカメラを起動"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。タップしてバイブレーションに設定します。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。タップしてミュートします。"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ミュート"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ミュートを解除"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"バイブレーション"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"追加"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> によるおすすめ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"コントロールを更新しました"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"デバイス: ロック状態"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN に英字や記号を含める"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>の確認"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN が間違っています"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5404e67..e2b9fac 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"მზის ამოსვლამდე"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ჩაირთოს <xliff:g id="TIME">%s</xliff:g>-ზე"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>-მდე"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"სიკაშკაშის შემცირება"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC გათიშულია"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ჩართულია"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ამ მოწყობილობას ფლობს <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ტელეფონისთვის გადაფურცლეთ ხატულადან"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ხმოვანი დახმარებისთვის გადაფურცლეთ ხატულადან"</string>
     <string name="camera_hint" msgid="4519495795000658637">"კამერისთვის გადაფურცლეთ ხატულადან"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. შეეხეთ დასადუმებლად."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"დადუმება"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"დადუმების მოხსნა"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ვიბრაცია"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"დამატება"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"შემოთავაზებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"მართვის საშუალებები განახლდა"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"მოწყობილ. ჩაკეტილია"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-კოდი შეიცავს ასოებს ან სიმბოლოებს"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"დაადასტურეთ <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN-კოდი არასწორია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 21c6201..1fbb8a5 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн шыққанға дейін"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> дейін"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Жарықтығын азайту"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өшірулі"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC қосулы"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Бұл құрылғы <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ұйымына тиесілі."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Телефонды ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Дауыс көмекшісін ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камераны ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Діріл режимін орнату үшін түртіңіз."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дыбысын өшіру үшін түртіңіз."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дыбысын өшіру"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дыбысын қосу"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дірілдету"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Енгізу"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ұсынған"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Басқару элементтері жаңартылды"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Құрылғы құлыпталды."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN коды әріптерден не таңбалардан құралады."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> растау"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN коды қате"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 567bfa8..e6f9668 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"រហូត​ដល់​ពេល​ថ្ងៃរះ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"បើកនៅម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"រហូតដល់ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"បន្ថយពន្លឺ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"បាន​បិទ NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"បាន​បើក NFC"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍​នេះគឺជា​កម្មសិទ្ធិរបស់​ស្ថាប័ន​អ្នក"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ឧបករណ៍នេះ​គឺជា​កម្មសិទ្ធិ​របស់ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"អូសចេញពីរូបតំណាងដើម្បីប្រើទូរស័ព្ទ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"អូសចេញពីរូបតំណាងដើម្បីប្រើជំនួយសំឡេង"</string>
     <string name="camera_hint" msgid="4519495795000658637">"អូសចេញពីរូបតំណាងដើម្បីប្រើកាមេរ៉ា"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s ។ ចុច​ដើម្បី​កំណត់​ឲ្យ​ញ័រ។"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s ។ ចុច​ដើម្បី​បិទ​សំឡេង។"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទ​សំឡេង"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើក​សំឡេង"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ញ័រ"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"បញ្ចូល"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"បាន​ណែនាំដោយ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"បានធ្វើបច្ចុប្បន្នភាពការគ្រប់គ្រង"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"បានចាក់សោ​ឧបករណ៍"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"កូដ PIN មាន​អក្សរ ឬនិមិត្តសញ្ញា"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ផ្ទៀងផ្ទាត់ <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"កូដ PIN មិន​ត្រឹមត្រូវ​"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e0ea3c2..15abcaa 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ಸಮಯದಲ್ಲಿ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ವರೆಗೂ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ಈ ಸಾಧನವು <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ಗೆ ಸೇರಿದೆ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ಫೋನ್‌ಗಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ಧ್ವನಿ ಸಹಾಯಕ್ಕಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ಕ್ಯಾಮರಾಗಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ವೈಬ್ರೇಟ್ ಮಾಡಲು ಹೊಂದಿಸುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ಅನ್‌ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ವೈಬ್ರೇಟ್‌"</string>
@@ -1038,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ಸೇರಿಸಿ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಸೂಚಿಸಿದೆ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ನಿಯಂತ್ರಣಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ಪಿನ್ ಅಕ್ಷರಗಳು ಅಥವಾ ಸಂಕೇತಗಳನ್ನು ಒಳಗೊಂಡಿದೆ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ತಪ್ಪಾದ ಪಿನ್‌"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 64e4a69..78c2958 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"일출까지"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>에 켜짐"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>까지"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"밝기 낮추기"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 사용 중지됨"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 사용 설정됨"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>에 속한 기기입니다."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"전화 기능을 사용하려면 아이콘에서 스와이프하세요."</string>
     <string name="voice_hint" msgid="7476017460191291417">"음성 지원을 사용하려면 아이콘에서 스와이프하세요."</string>
     <string name="camera_hint" msgid="4519495795000658637">"카메라를 사용하려면 아이콘에서 스와이프하세요."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. 탭하여 진동으로 설정하세요."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. 탭하여 음소거로 설정하세요."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"음소거"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"음소거 해제"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"진동"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"추가"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>에서 제안"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"컨트롤 업데이트됨"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"기기 잠김"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN에 문자나 기호가 포함됨"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> 확인"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"잘못된 PIN"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ecbcd55..7a4d7d2 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -94,7 +94,7 @@
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотту четке кагуу"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотту алдын ала көрүү"</string>
     <string name="screenshot_top_boundary" msgid="1500569103321300856">"Жогорку чеги"</string>
-    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Баскычтын чеги"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Төмөнкү чеги"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн чыкканга чейин"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Саат <xliff:g id="TIME">%s</xliff:g> күйөт"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> чейин"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Экрандын жарыктыгын төмөндөтүү"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өчүрүлгөн"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC иштетилген"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Бул түзмөк төмөнкүгө таандык: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Сүрөтчөнү сүрүп телефонго өтүңүз"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Сүрөтчөнү сүрүп үн жардамчысына өтүңүз"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Сүрөтчөнү сүрүп камерага өтүңүз"</string>
@@ -627,6 +630,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дирилдөөгө коюу үчүн басыңыз."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Үнүн өчүрүү үчүн басыңыз."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"үнсүз"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"үнүн чыгаруу"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дирилдөө"</string>
@@ -1040,6 +1045,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Кошуу"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> сунуштайт"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Башкаруу элементтери жаңырды"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Түзмөк кулпуланды"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгалардан же символдордон турат"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> түзмөгүн ырастаңыз"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN код туура эмес"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 98a75c2..7070fa1 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ຈົນກວ່າຕາເວັນຂຶ້ນ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ເປີດເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"ຈົນຮອດ <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ຫຼຸດຄວາມສະຫວ່າງ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ອຸ​ປະ​ກອນ​ນີ້​ເປັນ​ຂອງ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ໂທ​ລະ​ສັບ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ການ​ຊ່ວຍ​ທາງ​ສຽງ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ກ້ອງ​ຖ່າຍ​ຮູບ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນເຕືອນ."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ແຕະເພື່ອປິດສຽງ."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ສັ່ນເຕືອນ"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ເພີ່ມ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"ແນະນຳໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ອັບເດດການຄວບຄຸມແລ້ວ"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ອຸປະກອນຖືກລັອກໄວ້"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ປະກອບມີຕົວອັກສອນ ຫຼື ສັນຍາລັກ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ຢັ້ງຢືນ <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ບໍ່ຖືກຕ້ອງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f4a2a0d..ff69e05 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Iki saulėtekio"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Iki <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Šviesumo mažinimas"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"ALR"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"ALR išjungtas"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"ALR įjungtas"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Šis įrenginys priklauso „<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>“"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Perbraukite iš telefono piktogramos"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Perbraukite iš „Voice Assist“ piktogramos"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Perbraukite iš fotoaparato piktogramos"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Palieskite, kad nustatytumėte vibravimą."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Palieskite, kad nutildytumėte."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"nutildyti"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"įjungti garsą"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibruoti"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridėti"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Siūlo „<xliff:g id="APP">%s</xliff:g>“"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Valdikliai atnaujinti"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Įrenginys užrakintas"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodą sudaro raidės arba simboliai"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> patvirtinimas"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Netinkamas PIN kodas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index caca22c..18816ad 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Līdz saullēktam"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Līdz plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Spilgtuma samazināšana"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ir atspējoti"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ir iespējoti"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Šī ierīce pieder organizācijai <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Lai lietotu tālruni, velciet no ikonas"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Lai lietotu balss palīgu, velciet no ikonas"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Lai lietotu kameru, velciet no ikonas"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Pieskarieties, lai iestatītu vibrozvanu."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Pieskarieties, lai izslēgtu skaņu."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izslēgt skaņu"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ieslēgt skaņu"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrēt"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pievienot"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Ieteica: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Vadīklas atjauninātas"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Ierīce ir bloķēta"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ietver burtus vai simbolus."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifikācija: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nepareizs PIN"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b3b4a45..59fc2d4 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрејсонце"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Се вклучува во <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Намали ја осветленоста"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC е оневозможено"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC е овозможено"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Уредов е во сопственост на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Повлечете од иконата за телефонот"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Повлечете од иконата за гласовна помош"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Повлечете од иконата за камерата"</string>
@@ -505,7 +508,7 @@
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Безгласно"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
-    <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите тивки известувања"</string>
+    <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите бесчујни известувања"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известувањата се паузирани од „Не вознемирувај“"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Нема известувања"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Допрете за да се постави на вибрации."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Допрете за да се исклучи звукот."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"исклучен звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"вклучен звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрации"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено од <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите се ажурирани"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Уредот е заклучен"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-кодот содржи букви или симболи"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Потврдете го <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешен PIN"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 420de5b..44883d6d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"സ്ക്രീൻഷോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"സ്ക്രീൻഷോട്ട് ഡിസ്‌മിസ് ചെയ്യുക"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"സ്‌ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"മുകളിലുള്ള അതിർത്തി"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ചുവടെയുള്ള അതിർത്തി"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"സൂര്യോദയം വരെ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> വരെ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"തെളിച്ചം കുറയ്ക്കുക"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC പ്രവർത്തനക്ഷമമാക്കി"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ഈ ഉപകരണം <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> എന്ന സ്ഥാപനത്തിന്റേതാണ്"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ഫോൺ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="voice_hint" msgid="7476017460191291417">"വോയ്‌സ് അസിസ്റ്റിനായുള്ള ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ക്യാമറ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ നിങ്ങളുടെ സ്ഥാപനമൊരു സർട്ടിഫിക്കറ്റ് അതോറിറ്റി ഇൻസ്റ്റാൾ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ സുരക്ഷിത നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കപ്പെടുകയോ പരിഷ്കരിക്കപ്പെടുയോ ചെയ്തേക്കാം."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"നിങ്ങളുടെ ഉപകരണത്തിൽ ഒരു സർട്ടിഫിക്കറ്റ് അതോറിറ്റി ഇൻസ്റ്റാൾ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ സുരക്ഷിത നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കപ്പെടുകയോ പരിഷ്കരിക്കപ്പെടുയോ ചെയ്തേക്കാം."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"നിങ്ങളുടെ അഡ്‌മിൻ, നെറ്റ്‌വർക്ക് ലോഗിംഗ് ഓണാക്കിയിട്ടുണ്ട്, ഇതിന് നിങ്ങളുടെ ഉപകരണത്തിലെ ട്രാഫിക്ക് നിരീക്ഷിക്കാൻ കഴിയും."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"നിങ്ങളുടെ അഡ്‌മിൻ നെറ്റ്‌വർക്ക് ലോഗിംഗ് ഓണാക്കി, ഇത് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിലെ ട്രാഫിക് നിരീക്ഷിക്കുന്നു എന്നാൽ വ്യക്തിപരമായ പ്രൊഫൈലിലെ ട്രാഫിക് നിരീക്ഷിക്കുന്നില്ല."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"നിങ്ങൾ <xliff:g id="VPN_APP">%1$s</xliff:g> എന്ന ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"നിങ്ങൾ <xliff:g id="VPN_APP_0">%1$s</xliff:g>, <xliff:g id="VPN_APP_1">%2$s</xliff:g> എന്നീ ആപ്പുകളിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> ആപ്പിലേക്ക് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"മ്യൂട്ട് ചെയ്യുക"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"അൺമ്യൂട്ട് ചെയ്യുക"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ചേർക്കുക"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> നിർദ്ദേശിച്ചത്"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"നിയന്ത്രണങ്ങൾ അപ്ഡേറ്റ് ചെയ്തു"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ഉപകരണം ലോക്ക് ചെയ്തു"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"പിന്നിൽ അക്ഷരങ്ങളോ ചിഹ്നങ്ങളോ അടങ്ങിയിരിക്കുന്നു"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> പരിശോധിച്ചുറപ്പിക്കുക"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"പിൻ തെറ്റാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 63547d5..efb2711 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Нар мандах хүртэл"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-д"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> хүртэл"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Гэрэлтүүлгийг багасгах"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Гэрэлтүүлгийг багасгах"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-г цуцалсан"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-г идэвхжүүлсэн"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Энэ төхөөрөмж <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-д харьяалагддаг"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Утсыг гаргахын тулд дүрс тэмдгээс шудрах"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Дуут туслахыг нээхийн тулд дүрс тэмдгээс шудрах"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камер нээхийн тулд дүрс тэмдгийг шудрах"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Чичиргээнд тохируулахын тулд товшино уу."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дууг хаахын тулд товшино уу."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Хонхны горимыг өөрчлөхийн тулд товшино уу"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дууг хаах"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дууг нээх"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"чичрэх"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Нэмэх"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>-н санал болгосон"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Хяналтуудыг шинэчиллээ"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Төхөөрөмжийг түгжсэн"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН нь үсэг эсвэл дүрс тэмдэгт агуулдаг"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>-г бататгах"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ПИН код буруу байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index de0e7be..fcff3df 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉटवर स्क्रोल करा"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट डिसमिस करा"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉटचे पूर्वावलोकन"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"सर्वात वरची सीमा"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"तळाची सीमा"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयापर्यंत"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> वाजता सुरू होते"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> पर्यंत"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ब्राइटनेस कमी करा"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC अक्षम केले आहे"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC सक्षम केले आहे"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> चे आहे"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"फोनसाठी चिन्हावरून स्वाइप करा"</string>
     <string name="voice_hint" msgid="7476017460191291417">"व्हॉइस सहाय्यासाठी चिन्हावरून स्वाइप करा"</string>
     <string name="camera_hint" msgid="4519495795000658637">"कॅमेर्‍यासाठी चिन्हावरून स्वाइप करा"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"आपल्या संस्थेने आपल्या कार्य प्रोफाइलवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"या डिव्हाइसवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"आपल्या प्रशासकाने नेटवर्क लॉगिंग सुरू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे परीक्षण करते."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"तुमच्या ॲडमिनने नेटवर्क लॉग इन सुरू केले आहे, जे तुमच्या कार्य प्रोफाइलमधील रहदारीचे निरीक्षण करत असले तरी तुमच्या वैयक्तिक प्रोफाइलमधील रहदारीचे निरीक्षण करत नाही."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"तुम्‍ही <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसहित आपल्‍या नेटवर्क क्रिया मॉनिटर करू शकते."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"तुम्‍ही <xliff:g id="VPN_APP_0">%1$s</xliff:g> आणि <xliff:g id="VPN_APP_1">%2$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसहित आपल्‍या नेटवर्क क्रिया मॉनिटर करू शकते."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"तुमचे कार्य प्रोफाइल <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करण्यासाठी टॅप करा."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करा"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"म्यूट काढून टाका"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"व्हायब्रेट करा"</string>
@@ -1041,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"जोडा"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ने सुचवले आहे"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"नियंत्रणे अपडेट केली आहेत"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरे किंवा चिन्हे आहेत"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ची पडताळणी करा"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"चुकीचा पिन"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 319dbde..e723ec6 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hingga matahari trbt"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Dihidupkan pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hingga <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Kurangkan Kecerahan"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dilumpuhkan"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC didayakan"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Peranti ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Leret dari ikon untuk telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Leret dari ikon untuk bantuan suara"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Leret dari ikon untuk kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketik untuk menetapkan pada getar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketik untuk meredam."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"redam"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"nyahredam"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambah"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Dicadangkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kawalan dikemas kini"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Peranti dikunci"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN mengandungi huruf atau simbol"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Sahkan <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN salah"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 15ddf59..c57a94c 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"နေထွက်ချိန် အထိ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> တွင် ဖွင့်မည်"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> အထိ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"တောက်ပမှုကို လျှော့ရန်"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ကို ပိတ်ထားသည်"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ကို ဖွင့်ထားသည်"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ဤစက်ကို <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> က ပိုင်ဆိုင်သည်"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ဖုန်းအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"အသံအကူအညီအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ကင်မရာအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s။ အသံတိတ်ရန် တို့ပါ။"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံတိတ်ရန်"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"တုန်ခါမှု"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ထည့်ရန်"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> က အကြံပြုထားသည်"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ထိန်းချုပ်မှု အပ်ဒိတ်လုပ်ပြီးပြီ"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"စက်ကိုလော့ခ်ချထားသည်"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ပင်နံပါတ်တွင် စာလုံး သို့မဟုတ် သင်္ကေတများပါဝင်သည်"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ကို အတည်ပြုခြင်း"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ပင်နံပါတ် မှားနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1c2fa8a..997147d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til soloppgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Slås på klokken <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduser lysstyrken"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er slått av"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er slått på"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enheten tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Sveip ikonet for å åpne telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Sveip fra ikonet for å åpne talehjelp"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Sveip ikonet for å åpne kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trykk for å angi vibrasjon."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trykk for å slå av lyden."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"kutt lyden"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på lyden"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Legg til"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Foreslått av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollene er oppdatert"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Enheten er låst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koden inneholder bokstaver eller symboler"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Bekreft <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Feil PIN-kode"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 3ab0136f..e03ee5b 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रिनसट स्क्रोल गर्नुहोस्"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रिनसट हटाउनुहोस्"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रिनसटको पूर्वावलोकन"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"सिरानको सीमा"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"फेदको सीमा"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयसम्म"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> मा सक्रिय"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> सम्म"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"स्क्रिनको चमक घटाउनुहोस्"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC लाई असक्षम पारिएको छ"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC लाई सक्षम पारिएको छ"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> को स्वामित्वमा छ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"फोनको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
     <string name="voice_hint" msgid="7476017460191291417">"आवाज सहायताका लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
     <string name="camera_hint" msgid="4519495795000658637">"क्यामेराको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"तपाईंको संगठनले तपाईंको कार्य प्रोफाइलमा एउटा प्रमाणपत्र सम्बन्धी अख्तियार सुविधा स्थापना गरेको छ। तपाईंको सुरक्षित नेटवर्क ट्राफिकको अनुगमन वा परिमार्जन हुनसक्छ।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"यस यन्त्रमा एउटा प्रमाणपत्र सम्बन्धी अख्तियार सुविधा स्थापना गरिएको छ। तपाईंको सुरक्षित नेटवर्कको ट्राफिकको अनुगमन वा परिमार्जन हुनसक्छ।"</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"तपाईंका प्रशासकले तपाईंको यन्त्रमा ट्राफिकको अनुगमन गर्ने नेटवर्क लग गर्ने प्रक्रियालाई सक्रिय गर्नुभएको छ।"</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"तपाईंका एड्मिनले \'नेटवर्क लगिङ\' सुविधा अन गर्नुभएको छ। यो सुविधाले तपाईंको कार्य प्रोफाइलको ट्राफिक अनुगमन गर्छ तर व्यक्तिगत प्रोफाइलको ट्राफिक भने अनुगमन गर्दैन।"</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"तपाईं इमेल, एप र वेबसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="VPN_APP">%1$s</xliff:g> मा जडान हुनुहुन्छ।"</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"तपाईं इमेल, एप र वेबसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="VPN_APP_0">%1$s</xliff:g> र <xliff:g id="VPN_APP_1">%2$s</xliff:g> मा जडान हुनुहुन्छ।"</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"तपाईंको कार्य प्रोफाइल तपाईंका इमेल, एप र वेबसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="VPN_APP">%1$s</xliff:g> मा जडान छ।"</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। म्यूट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। कम्पन मोडमा सेट गर्न ट्याप गर्नुहोस्।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। म्यूट गर्न ट्याप गर्नुहोस्।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्युट गर्नुहोस्"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्युट गर्नुहोस्"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"कम्पन गर्नुहोस्"</string>
@@ -1041,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"थप्नुहोस्"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ले सिफारिस गरेको"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"नियन्त्रण सुविधाहरू अद्यावधिक गरिए"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN मा अक्षर वा चिन्हहरू समाविष्ट हुन्छन्"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> पुष्टि गर्नुहोस्"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN मिलेन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index dcadbf5..8ffc3f4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Helderheid verlagen"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is uitgeschakeld"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is ingeschakeld"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipen voor telefoon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipen vanaf icoon voor spraakassistent"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Vegen voor camera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om in te stellen op trillen."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om geluid uit te zetten."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"trillen"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Toevoegen"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Voorgesteld door <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Bedieningselementen geüpdated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Apparaat vergrendeld"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pincode bevat letters of symbolen"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> verifiëren"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Onjuiste pincode"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 955c08a..f03c31d 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ସକାଳ ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ରେ ଚାଲୁ ହେବ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ଉଜ୍ଜ୍ୱଳତା କମାନ୍ତୁ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ଅକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ସକ୍ଷମ କରାଯାଇଛି"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ର ଅଟେ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ଫୋନ୍‍ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ଭଏସ୍‍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"କ୍ୟାମେରା ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍‌ ମ୍ୟୁଟ୍‍ କରାଯାଇପାରେ।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ଭାଇବ୍ରେଟରେ ସେଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ୍"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ଅନ୍‍-ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ଭାଇବ୍ରେଟ୍"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ଯୋଗ କରନ୍ତୁ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରସ୍ତାବିତ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଅପଡେଟ୍ କରାଯାଇଛି"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ଡିଭାଇସ୍ ଲକ୍ ହୋଇଯାଇଛି"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ପ୍ରତୀକଗୁଡ଼ିକ ଥାଏ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ଭୁଲ PIN"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 47f56bd..459b163 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"ਉੱਪਰ ਦੀ ਸੀਮਾ"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਚਾਲੂ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਤੱਕ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ਚਮਕ ਘਟਾਓ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ਫ਼ੋਨ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ਕੈਮਰੇ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਇੱਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਅਥਾਰਟੀ ਸਥਾਪਤ ਕੀਤੀ ਗਈ ਹੈ। ਤੁਹਾਡੇ ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੋਧਿਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ਇੱਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਅਥਾਰਟੀ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਤੁਹਾਡੇ ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੋਧਿਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ।"</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗ-ਇਨ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ ਪਰ ਤੁਹਾਡੀ ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਨਹੀਂ।"</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"ਤੁਸੀਂ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"ਤੁਸੀਂ <xliff:g id="VPN_APP_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="VPN_APP_1">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ਥਰਥਰਾਹਟ \'ਤੇ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ਮਿਊਟ ਕਰੋ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ਅਣਮਿਊਟ ਕਰੋ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ਥਰਥਰਾਹਟ"</string>
@@ -1041,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ਵੱਲੋਂ ਸੁਝਾਇਆ ਗਿਆ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ਕੰਟਰੋਲ ਅੱਪਡੇਟ ਕੀਤੇ ਗਏ"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਹਨ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ਗਲਤ ਪਿੰਨ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 59c9f52..e16b5ec 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"Przewiń zrzut ekranu"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zamknij zrzut ekranu"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Podgląd zrzutu ekranu"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"Górna granica"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Dolna granica"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
@@ -418,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do wschodu słońca"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Włącz o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Zmniejsz jasność"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"Komunikacja NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Komunikacja NFC jest wyłączona"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Komunikacja NFC jest włączona"</string>
@@ -452,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Właściciel tego urządzenia: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Aby włączyć telefon, przesuń palcem od ikony"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Aby uzyskać pomoc głosową, przesuń palcem od ikony"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Przesuń palcem od ikony, by włączyć aparat"</string>
@@ -552,8 +553,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Twoja organizacja zainstalowała urząd certyfikacji w Twoim profilu służbowym. Zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Urząd certyfikacji zainstalowany na tym urządzeniu. Twój zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim profilu służbowym, ale nie na profilu osobistym."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Łączysz się z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Łączysz się z aplikacjami <xliff:g id="VPN_APP_0">%1$s</xliff:g> i <xliff:g id="VPN_APP_1">%2$s</xliff:g>, które mogą monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Twój profil służbowy jest połączony z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
@@ -634,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Kliknij, by włączyć wibracje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Kliknij, by wyciszyć."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"wycisz"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"wyłącz wyciszenie"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"włącz wibracje"</string>
@@ -1053,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugestia: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Zaktualizowano elementy sterujące"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Urządzenie zablokowane"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kod PIN zawiera litery lub symbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Sprawdź urządzenie <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nieprawidłowy kod PIN"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index fca802d..efe0f06 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir brilho"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -791,7 +796,7 @@
     <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Parar"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"Avançar"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
-    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
+    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Voltar"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avançar rapidamente"</string>
     <string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9b4d45b..3a82feb 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até ao amanhecer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativado à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir o brilho"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"O NFC está desativado"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"O NFC está ativado"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à entidade <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Deslize rapid. a partir do ícone para aceder ao telemóvel"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Deslize rapid. a partir do ícone para aceder ao assist. voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Deslize rapidamente a partir do ícone para aceder à câmara"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para ativar a vibração."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para desativar o som."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"reativar som"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlos atualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Validar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index fca802d..efe0f06 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir brilho"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -791,7 +796,7 @@
     <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Parar"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"Avançar"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
-    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
+    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Voltar"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avançar rapidamente"</string>
     <string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3a06921..18093b4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Până la răsărit"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activată la <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Până la <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduceți luminozitatea"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Serviciul NFC este dezactivat"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Serviciul NFC este activat"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Glisați dinspre telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Glisați dinspre pictogramă pentru asistentul vocal"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Glisați pentru a fotografia"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Atingeți pentru a seta pe vibrații."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Atingeți pentru a dezactiva sunetul."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"dezactivați sunetul"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activați sunetul"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrații"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adăugați"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerat de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"S-au actualizat comenzile"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispozitiv blocat"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Codul PIN conține litere sau simboluri"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificați <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Cod PIN greșit"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a81401a..a9f7c02 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До рассвета"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Включить в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Уменьшение яркости"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"Модуль NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Модуль NFC отключен"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Модуль NFC включен"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Этим устройством владеет организация \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Телефон: проведите от значка"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Аудиоподсказки: проведите от значка"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камера: проведите от значка"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Нажмите, чтобы включить вибрацию."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Нажмите, чтобы выключить звук."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"включить звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"включить вибрацию"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавить"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено приложением \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы управления обновлены."</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Устройство заблокировано"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код содержит буквы или символы"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Подтвердите устройство \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Неверный PIN-код"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index f62eae0..5134e04 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"හිරු නගින තෙක්"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ට ක්‍රියාත්මකයි"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> තෙක්"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"දීප්තිය අඩු කරන්න"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"දීප්තිය අඩු කරන්න"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC අබලයි"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC සබලයි"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> සංවිධානයට අයිතිය"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"දුරකථනය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <string name="voice_hint" msgid="7476017460191291417">"හඬ සහාය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <string name="camera_hint" msgid="4519495795000658637">"කැමරාව සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. කම්පනය කිරීමට සකස් කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"නාදකය වෙනස් කිරීමට තට්ටු කරන්න"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"නිහඬ කරන්න"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"නිශ්ශබ්දතාවය ඉවත් කරන්න"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"කම්පනය"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"එක් කරන්න"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"යෝජනා කළේ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"පාලන යාවත්කාලීනයි"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"උපාංගය අගුලු දමා ඇත"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN හි අකුරු හෝ සංකේත අඩංගු වේ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> සත්‍යාපනය කරන්න"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"වැරදි PIN එකකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 927b2ac..d514b66 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do východu slnka"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapne sa o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Znížiť jas"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je deaktivované"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je aktivované"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zariadení patrí organizácii <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefón otvoríte prejdením prstom od ikony"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Hlasového asistenta otvoríte prejdením prstom od ikony"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otvoríte prejdením prstom od ikony"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrovanie."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridať"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Navrhuje <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládanie bolo aktualizované"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uzamknuté zariadenie"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN obsahuje písmená či symboly"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>, overenie"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nesprávny PIN"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 881ba91..b7b2dd0 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do sončnega vzhoda"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Vklop ob <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Zmanjšanje svetlosti"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Tehnologija NFC je onemogočena"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Tehnologija NFC je omogočena"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ta naprava pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Povlecite z ikone za telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Povlecite z ikone za glasovnega pomočnika"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Povlecite z ikone za fotoaparat"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dotaknite se, če želite nastaviti vibriranje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dotaknite se, če želite izklopiti zvok."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vklop zvoka"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlagala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrolniki so posodobljeni"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Naprava je zaklenjena"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Koda PIN vsebuje črke ali simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Preverjanje naprave <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Napačna koda PIN"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 29d1661..9f4c1e1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Deri në lindje të diellit"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktiv në <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Deri në <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Redukto ndriçimin"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC është çaktivizuar"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC është aktivizuar"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Kjo pajisje i përket <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Rrëshqit për të hapur telefonin"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Rrëshqit për të hapur ndihmën zanore"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Rrëshqit për të hapur kamerën"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trokit për ta vendosur në dridhje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trokit për ta çaktivizuar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"lësho dridhje"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Shto"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugjeruar nga <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollet u përditësuan"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Pajisja është e kyçur"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kodi PIN përmban shkronja ose simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifiko <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Kod PIN i gabuar"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c021bfa..5c2fbac 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изласка сунца"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Укључује се у <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Смањи осветљеност"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC је онемогућен"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC је омогућен"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Овај уређај припада организацији <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Превуците од иконе за телефон"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Превуците од иконе за гласовну помоћ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Превуците од иконе за камеру"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Додирните да бисте подесили на вибрацију."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Додирните да бисте искључили звук."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"искључите звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"укључите звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрација"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предлаже <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контроле су ажуриране"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Уређај је закључан"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN садржи слова или симболе"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Верификујте: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешан PIN"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e38d7cd..5ca41ed 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Till soluppgången"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktivera kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Till <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Minska ljusstyrkan"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC är inaktiverat"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC är aktiverat"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Den här enheten tillhör <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Svep från ikonen och öppna telefonen"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Svep från ikonen och öppna röstassistenten"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Svep från ikonen och öppna kameran"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryck här om du vill aktivera vibrationsläget."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryck här om du vill stänga av ljudet."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på ljudet"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lägg till"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Förslag från <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Snabbkontroller uppdaterade"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Enheten är låst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden innehåller bokstäver eller symboler"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifiera <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Fel pinkod"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a775d14..768e10c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hadi macheo"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Itawashwa saa <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hadi saa <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Punguza Ung\'aavu"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC imezimwa"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC imewashwa"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Kifaa hiki kinamilikiwa na <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telezesha kidole kutoka kwa aikoni ili ufikie simu"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Telezesha kidole kutoka aikoni ili upate mapendekezo ya sauti"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Telezesha kidole kutoka aikoni ili ufikie kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Gusa ili uweke mtetemo."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Gusa ili usitishe."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"zima sauti"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"washa sauti"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tetema"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Weka"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Kimependekezwa na <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Umesasisha vidhibiti"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Kifaa kimefungwa"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ina herufi au alama"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Thibitisha <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nambari ya PIN si sahihi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 335a529..2ea5a6a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"காலை வரை"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>க்கு ஆன் செய்"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> வரை"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ஒளிர்வைக் குறை"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC முடக்கப்பட்டது"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC இயக்கப்பட்டது"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"இந்த சாதனம் <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> நிறுவனத்துக்கு சொந்தமானது"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ஃபோனிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
     <string name="voice_hint" msgid="7476017460191291417">"குரல் உதவிக்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
     <string name="camera_hint" msgid="4519495795000658637">"கேமராவிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும்."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ஒலியடக்க, தட்டவும்."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ஒலியடக்கும்"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ஒலி இயக்கும்"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"அதிர்வுறும்"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"சேர்"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ஆப்ஸால் பரிந்துரைக்கப்பட்டது"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"கட்டுப்பாடுகள் மாற்றப்பட்டன"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"சாதனம் பூட்டப்பட்டது"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"பின்னில் எழுத்துகள் அல்லது குறிகள் உள்ளன"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ஐச் சரிபார்த்தல்"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"தவறான பின்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 8013d6e..03af2a0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"స్క్రీన్‌షాట్‌కు స్క్రోల్ చేయండి"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"స్క్రీన్‌షాట్‌ను విస్మరించు"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"స్క్రీన్‌షాట్ ప్రివ్యూ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"ఎగువ సరిహద్దు"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"దిగువ సరిహద్దు"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"స్క్రీన్ రికార్డర్"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్‌గోయింగ్ నోటిఫికేషన్"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"సూర్యోదయం వరకు"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> కు ఆన్ అవుతుంది"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> వరకు"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ప్రకాశాన్ని తగ్గించండి"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ప్రారంభించబడింది"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్‌లాక్ చేయండి"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>కు చెందినది"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ఫోన్ కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
     <string name="voice_hint" msgid="7476017460191291417">"వాయిస్ అసిస్టెంట్ చిహ్నం నుండి స్వైప్"</string>
     <string name="camera_hint" msgid="4519495795000658637">"కెమెరా కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"మీ కార్యాలయ ప్రొఫైల్‌లో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్‌స్టాల్ చేసింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ఈ పరికరంలో ప్రమాణపత్ర అధికారం ఇన్‌స్టాల్ చేయబడింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"మీ అడ్మిన్ నెట్‌వర్క్ లాగింగ్‌ను ఆన్ చేశారు, ఇది మీ వర్క్ ప్రొఫైల్‌లోని ట్రాఫిక్‌ను పర్యవేక్షిస్తుంది కానీ మీ వ్యక్తిగత ప్రొఫైల్‌లో కాదు."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"మీ కార్యాలయ ప్రొఫైల్ ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. వైబ్రేట్ అయ్యేలా సెట్ చేయడం కోసం నొక్కండి."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. మ్యూట్ చేయడానికి నొక్కండి."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"మ్యూట్ చేయి"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్‌మ్యూట్ చేయి"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"జోడించండి"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ద్వారా సూచించబడింది"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"నియంత్రణలు అప్‌డేట్ అయ్యాయి"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"పరికరంలాక్ చేయబడింది"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"పిన్ అక్షరాలను లేదా చిహ్నాలను కలిగి ఉంది"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ను వెరిఫై చేయండి"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"పిన్ తప్పు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c55b7f0..5e37ed8 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"จนพระอาทิตย์ขึ้น"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"เปิดเวลา <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"จนถึง <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ลดความสว่าง"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ถูกปิดใช้งาน"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"เปิดใช้งาน NFC แล้ว"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> เป็นเจ้าของอุปกรณ์นี้"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"เลื่อนไอคอนโทรศัพท์"</string>
     <string name="voice_hint" msgid="7476017460191291417">"เลื่อนไอคอนตัวช่วยเสียง"</string>
     <string name="camera_hint" msgid="4519495795000658637">"เลื่อนไอคอนกล้อง"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s แตะเพื่อตั้งค่าให้สั่น"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s แตะเพื่อปิดเสียง"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ปิดเสียง"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"เปิดเสียง"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"สั่น"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"เพิ่ม"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"แนะนำโดย <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"อัปเดตตัวควบคุมแล้ว"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"อุปกรณ์ถูกล็อก"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ประกอบด้วยตัวอักษรหรือสัญลักษณ์"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ยืนยัน <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ไม่ถูกต้อง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 33bd659..18313e4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Bawasan ang Liwanag"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Naka-disable ang NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Naka-enable ang NFC"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Pagmamay-ari ng <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ang device na ito"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Mag-swipe mula sa icon para sa telepono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Mag-swipe mula sa icon para sa voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Mag-swipe mula sa icon para sa camera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. I-tap upang itakda na mag-vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. I-tap upang i-mute."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"i-mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"i-unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"i-vibrate"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Idagdag"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Na-update na ang mga kontrol"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Naka-lock ang device"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"May mga titik o simbolo ang PIN"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"I-verify ang <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Maling PIN"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4bacfb9..6b3015c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sabaha kadar"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Açılacağı saat: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Şu saate kadar: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Parlaklığı Azalt"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC devre dışı"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC etkin"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> adlı kuruluşa ait"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefon için, simgeden hızlıca kaydırın"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Sesli yardım için, simgeden hızlıca kaydırın"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kamera için, simgeden hızlıca kaydırın"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Titreşime ayarlamak için dokunun."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sesi kapatmak için dokunun."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi  kapat"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titreşim"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ekle"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tarafından önerildi"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Denetimler güncellendi"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilitlendi"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN, harf veya simge içerir"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Yanlış PIN"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4a0746c..12b4830 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До сходу сонця"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Вмикається о <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Зменшувати яскравість"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC вимкнено"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ввімкнено"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Цей пристрій належить організації \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Телефон: проведіть пальцем від значка"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Голосові підказки: проведіть пальцем від значка"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камера: проведіть пальцем від значка"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Торкніться, щоб налаштувати вібросигнал."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Торкніться, щоб вимкнути звук."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"вимкнути звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"увімкнути звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"увімкнути вібросигнал"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додати"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Запропоновано додатком <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Елементи керування оновлено"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Пристрій заблоковано"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код містить літери чи символи"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Неправильний PIN-код"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f2e0273..3668f7e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"طلوع آفتاب تک"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"آن ہوگی بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> تک"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"چمک کم کریں"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‏NFC غیر فعال ہے"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏NFC فعال ہے"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> کا ہے"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"فون کیلئے آئیکن سے سوائپ کریں"</string>
     <string name="voice_hint" msgid="7476017460191291417">"صوتی معاون کیلئے آئیکن سے سوائپ کریں"</string>
     <string name="camera_hint" msgid="4519495795000658637">"کیمرہ کیلئے آئیکن سے سوائپ کریں"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏‎%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"خاموش کریں"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"غیر خاموش کریں"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"وائبریٹ"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"شامل کریں"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> کی طرف سے تجویز کردہ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"کنٹرولز اپ ڈیٹ کیے گئے"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"آلہ مقفل کر دیا گیا"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‏PIN میں حروف یا علامات شامل ہیں"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"‫<xliff:g id="DEVICE">%s</xliff:g> کی تصدیق کریں"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"‏غلط PIN"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index fab65b1..0732c7f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"Skrinshotni aylantirish"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Skrinshotni yopish"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Skrinshotga razm solish"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"Yuqori chegara"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Quyi chegara"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
@@ -414,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Quyosh chiqqunicha"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> da yoqiladi"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> gacha"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Yorqinlikni pasaytirish"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Yorqinlikni pasaytirish"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC o‘chiq"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC yoniq"</string>
@@ -448,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tashkilotiga tegishli"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefonni ochish uchun suring"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Ovozli yordam: belgidan boshlab suring"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kamerani ochish uchun suring"</string>
@@ -546,8 +546,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Tashkilotingiz ishchi profilingizga CA sertifikatini o‘rnatdi. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Qurilmada CA sertifikati o‘rnatilgan. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator qurilmangizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administrator ish profilingizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi (shaxsiy profildan maʼlumotlar olinmaydi)."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> va <xliff:g id="VPN_APP_1">%2$s</xliff:g> ilovalari ishga tushirilgan. Ular tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Ishchi profilingizda tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin bo‘lgan <xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan."</string>
@@ -628,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tebranishni yoqish uchun ustiga bosing."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ovozsiz qilish uchun ustiga bosing."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Jiringlagich rejimini oʻzgartirish uchun bosing"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ovozsiz qilish"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ovozni yoqish"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tebranish"</string>
@@ -1041,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Kiritish"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> taklif etgan"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Boshqaruv elementlari yangilandi"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Qurilma qulflandi"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Tekshirish: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN kod xato"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 366f755..cc89303 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Cho đến khi trời sáng"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bật vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Cho đến <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Giảm độ sáng"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC đã được tắt"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC đã được bật"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Thiết bị này thuộc về <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Vuốt từ biểu tượng để mở điện thoại"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Vuốt từ biểu tượng để mở trợ lý thoại"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Vuốt từ biểu tượng để mở máy ảnh"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Nhấn để đặt chế độ rung."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Nhấn để tắt tiếng."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"tắt tiếng"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"bật tiếng"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rung"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Thêm"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Do <xliff:g id="APP">%s</xliff:g> đề xuất"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Đã cập nhật các tùy chọn điều khiển"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Đã khóa thiết bị"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Mã PIN chứa các ký tự hoặc ký hiệu"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Xác minh <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Mã PIN sai"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c25ad27..92f9e67 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出时关闭"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"在<xliff:g id="TIME">%s</xliff:g> 开启"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直到<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"调低亮度"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已启用"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"此设备归<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>所有"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"滑动图标即可拨打电话"</string>
     <string name="voice_hint" msgid="7476017460191291417">"滑动图标即可打开语音助理"</string>
     <string name="camera_hint" msgid="4519495795000658637">"滑动图标即可打开相机"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。点按即可设为振动。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。点按即可设为静音。"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"静音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消静音"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"振动"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"添加"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"来自<xliff:g id="APP">%s</xliff:g>的建议"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"控件已更新"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"设备已锁定"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 码由字母或符号组成"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"验证<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 码错误"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index aa7b47a..d2a232b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出時關閉"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"於<xliff:g id="TIME">%s</xliff:g>開啟"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直至<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"調低亮度"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"調低亮度"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"此裝置屬於「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"從圖示滑動即可使用手機功能"</string>
     <string name="voice_hint" msgid="7476017460191291417">"從圖示滑動即可使用語音助手"</string>
     <string name="camera_hint" msgid="4519495795000658637">"從圖示滑動即可使用相機功能"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕按即可設為震動。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕按即可設為靜音。"</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"輕按即可變更響鈴模式"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"由「<xliff:g id="APP">%s</xliff:g>」提供的建議"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"裝置已上鎖"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 含有字母或符號"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"驗證<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 錯誤"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ca8db2e..396484a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -71,7 +71,7 @@
     <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"目前登入這部裝置的使用者無法開啟無線偵錯功能。如要使用這項功能,請切換到主要使用者。"</string>
     <string name="usb_contaminant_title" msgid="894052515034594113">"USB 連接埠已停用"</string>
     <string name="usb_contaminant_message" msgid="7730476585174719805">"為了避免液體或灰塵導致你的裝置受損,系統已停用 USB 連接埠,因此目前無法偵測任何配件。\n\n系統會在可繼續使用 USB 連接埠時通知你。"</string>
-    <string name="usb_port_enabled" msgid="531823867664717018">"USB 通訊埠已啟用,可偵測充電器和配件"</string>
+    <string name="usb_port_enabled" msgid="531823867664717018">"USB 連接埠已啟用,可偵測充電器和配件"</string>
     <string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"啟用 USB 連接埠"</string>
     <string name="learn_more" msgid="4690632085667273811">"瞭解詳情"</string>
     <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"於日出時關閉"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"開啟時間:<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"關閉時間:<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"調低亮度"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"滑動手機圖示即可啟用"</string>
     <string name="voice_hint" msgid="7476017460191291417">"滑動語音小幫手圖示即可啟用"</string>
     <string name="camera_hint" msgid="4519495795000658637">"滑動相機圖示即可啟用"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕觸即可設為震動。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕觸即可設為靜音。"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"來自「<xliff:g id="APP">%s</xliff:g>」的建議"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"裝置已鎖定"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 碼含有字母或符號"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"驗證「<xliff:g id="DEVICE">%s</xliff:g>」"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 碼錯誤"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 371702f..d4e05d0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuze kube sekuphumeni kwelanga"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Kuvulwe ngo-<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuze kube ngu-<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Nciphisa ukukhanya"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"I-NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"I-NFC ikhutshaziwe"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"I-NFC inikwe amandla"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Le divayisi ngeye-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swayiphela ifoni kusukela kusithonjana"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swayiphela isilekeleli sezwi kusukela kusithonjana"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swayiphela ikhamela kusukela kusithonjana"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Thepha ukuze usethele ekudlidlizeni."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Thepha ukuze uthulise."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"thulisa"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"susa ukuthula"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dlidliza"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Engeza"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Kuphakanyiswe ngu-<xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Izilawuli zibuyekeziwe"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Idivayisi ikhiyiwe"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Iphinikhodi iqukethe amaletha namasimbui"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Qinisekisa i-<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Iphinikhodi engalungile"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0893c14..b75a0bc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -91,9 +91,6 @@
     <!-- The number of columns in the QuickSettings -->
     <integer name="quick_settings_num_columns">3</integer>
 
-    <!-- The number of columns in the Quick Settings customizer -->
-    <integer name="quick_settings_edit_num_columns">@integer/quick_settings_num_columns</integer>
-
     <!-- The number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">3</integer>
 
@@ -315,7 +312,6 @@
         <item>com.android.systemui.accessibility.SystemActions</item>
         <item>com.android.systemui.toast.ToastUI</item>
         <item>com.android.systemui.wmshell.WMShell</item>
-        <item>com.android.systemui.people.widget.PeopleSpaceWidgetEnabler</item>
     </string-array>
 
     <!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
@@ -416,6 +412,9 @@
     <!-- Whether or not child notifications that are part of a group will have shadows. -->
     <bool name="config_enableShadowOnChildNotifications">true</bool>
 
+    <!-- If true, group numbers are shown in the expander instead of via "+N" overflow number -->
+    <bool name="config_showNotificationGroupCountInExpander">true</bool>
+
     <!-- Whether or not a view containing child notifications will have a custom background when
          it has been expanded to reveal its children. -->
     <bool name="config_showGroupNotificationBgWhenExpanded">false</bool>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2d202fb..ec26b8d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -608,6 +608,11 @@
         <item name="android:windowCloseOnTouchOutside">true</item>
     </style>
 
+    <!-- Privacy dialog -->
+    <style name="PrivacyDialog" parent="ScreenRecord">
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+    </style>
+
     <!-- USB Contaminant dialog -->
     <style name ="USBContaminant" />
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 87f6b82..568fdea 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.shared.system;
 
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+
 import android.app.PictureInPictureParams;
 import android.app.WindowConfiguration;
 import android.graphics.Point;
@@ -44,6 +46,9 @@
     public static final int ACTIVITY_TYPE_ASSISTANT = WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
     public final int activityType;
 
+    public static final int TYPE_NAVIGATION_BAR = WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+    public final int windowType;
+
     public final int taskId;
     public final SurfaceControlCompat leash;
     public final boolean isTranslucent;
@@ -74,6 +79,7 @@
         contentInsets = app.contentInsets;
         activityType = app.windowConfiguration.getActivityType();
         pictureInPictureParams = app.pictureInPictureParams;
+        windowType = app.windowType;
 
         mStartLeash = app.startLeash;
     }
@@ -114,6 +120,7 @@
             activityType = ACTIVITY_TYPE_UNDEFINED;
         }
         pictureInPictureParams = null;
+        windowType = INVALID_WINDOW_TYPE;
         mStartLeash = null;
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5f6fd30..a2d7707 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -29,12 +29,17 @@
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.MathUtils;
 import android.util.TypedValue;
+import android.view.Gravity;
 import android.view.MotionEvent;
+import android.view.OrientationEventListener;
 import android.view.VelocityTracker;
+import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewPropertyAnimator;
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimationControlListener;
@@ -55,6 +60,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 import java.util.List;
 
@@ -99,6 +105,12 @@
     private boolean mDisappearAnimRunning;
     private SwipeListener mSwipeListener;
 
+    private boolean mIsSecurityViewLeftAligned = true;
+    private boolean mOneHandedMode = false;
+    private SecurityMode mSecurityMode = SecurityMode.Invalid;
+    private ViewPropertyAnimator mRunningOneHandedAnimator;
+    private final OrientationEventListener mOrientationEventListener;
+
     private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
             new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
 
@@ -157,16 +169,20 @@
     // Used to notify the container when something interesting happens.
     public interface SecurityCallback {
         boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
+
         void userActivity();
+
         void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
 
         /**
-         * @param strongAuth wheher the user has authenticated with strong authentication like
-         *                   pattern, password or PIN but not by trust agents or fingerprint
+         * @param strongAuth   wheher the user has authenticated with strong authentication like
+         *                     pattern, password or PIN but not by trust agents or fingerprint
          * @param targetUserId a user that needs to be the foreground user at the finish completion.
          */
         void finish(boolean strongAuth, int targetUserId);
+
         void reset();
+
         void onCancelClicked();
     }
 
@@ -224,12 +240,136 @@
         super(context, attrs, defStyle);
         mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
         mViewConfiguration = ViewConfiguration.get(context);
+
+        mOrientationEventListener = new OrientationEventListener(context) {
+            @Override
+            public void onOrientationChanged(int orientation) {
+                updateLayoutForSecurityMode(mSecurityMode);
+            }
+        };
     }
 
     void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
+        mSecurityMode = securityMode;
         mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
         updateBiometricRetry(securityMode, faceAuthEnabled);
 
+        updateLayoutForSecurityMode(securityMode);
+        mOrientationEventListener.enable();
+    }
+
+    void updateLayoutForSecurityMode(SecurityMode securityMode) {
+        mSecurityMode = securityMode;
+        mOneHandedMode = canUseOneHandedBouncer();
+
+        if (mOneHandedMode) {
+            mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext);
+        }
+
+        updateSecurityViewGravity();
+        updateSecurityViewLocation(false);
+    }
+
+    /** Return whether the one-handed keyguard should be enabled. */
+    private boolean canUseOneHandedBouncer() {
+        // Is it enabled?
+        if (!getResources().getBoolean(
+                com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
+            return false;
+        }
+
+        if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) {
+            return false;
+        }
+
+        return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
+    }
+
+    /** Read whether the one-handed keyguard should be on the left/right from settings. */
+    private boolean isOneHandedKeyguardLeftAligned(Context context) {
+        try {
+            return Settings.Global.getInt(context.getContentResolver(),
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
+                    == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
+        } catch (Settings.SettingNotFoundException ex) {
+            return true;
+        }
+    }
+
+    private void updateSecurityViewGravity() {
+        View securityView = findKeyguardSecurityView();
+
+        if (securityView == null) {
+            return;
+        }
+
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams();
+
+        if (mOneHandedMode) {
+            lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
+        } else {
+            lp.gravity = Gravity.CENTER_HORIZONTAL;
+        }
+
+        securityView.setLayoutParams(lp);
+    }
+
+    /**
+     * Moves the inner security view to the correct location (in one handed mode) with animation.
+     * This is triggered when the user taps on the side of the screen that is not currently occupied
+     * by the security view .
+     */
+    private void updateSecurityViewLocation(boolean animate) {
+        View securityView = findKeyguardSecurityView();
+
+        if (securityView == null) {
+            return;
+        }
+
+        if (!mOneHandedMode) {
+            securityView.setTranslationX(0);
+            return;
+        }
+
+        if (mRunningOneHandedAnimator != null) {
+            mRunningOneHandedAnimator.cancel();
+            mRunningOneHandedAnimator = null;
+        }
+
+        int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
+
+        if (animate) {
+            mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation);
+            mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+            mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mRunningOneHandedAnimator = null;
+                }
+            });
+
+            mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mRunningOneHandedAnimator.start();
+        } else {
+            securityView.setTranslationX(targetTranslation);
+        }
+    }
+
+    @Nullable
+    private KeyguardSecurityViewFlipper findKeyguardSecurityView() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+
+            if (isKeyguardSecurityView(child)) {
+                return (KeyguardSecurityViewFlipper) child;
+            }
+        }
+
+        return null;
+    }
+
+    private boolean isKeyguardSecurityView(View view) {
+        return view instanceof KeyguardSecurityViewFlipper;
     }
 
     public void onPause() {
@@ -238,6 +378,7 @@
             mAlertDialog = null;
         }
         mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
+        mOrientationEventListener.disable();
     }
 
     @Override
@@ -319,19 +460,44 @@
                 if (mSwipeListener != null) {
                     mSwipeListener.onSwipeUp();
                 }
+            } else {
+                if (!mIsDragging) {
+                    handleTap(event);
+                }
             }
         }
         return true;
     }
 
+    private void handleTap(MotionEvent event) {
+        // If we're using a fullscreen security mode, skip
+        if (!mOneHandedMode) {
+            return;
+        }
+
+        // Did the tap hit the "other" side of the bouncer?
+        if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f))
+                || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) {
+            mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned;
+
+            Settings.Global.putInt(
+                    mContext.getContentResolver(),
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
+                    mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
+                            : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
+
+            updateSecurityViewLocation(true);
+        }
+    }
+
     void setSwipeListener(SwipeListener swipeListener) {
         mSwipeListener = swipeListener;
     }
 
     private void startSpringAnimation(float startVelocity) {
         mSpringAnimation
-            .setStartVelocity(startVelocity)
-            .animateToFinalPosition(0);
+                .setStartVelocity(startVelocity)
+                .animateToFinalPosition(0);
     }
 
     public void startDisappearAnimation(SecurityMode securitySelection) {
@@ -441,18 +607,17 @@
         return insets.inset(0, 0, 0, inset);
     }
 
-
     private void showDialog(String title, String message) {
         if (mAlertDialog != null) {
             mAlertDialog.dismiss();
         }
 
         mAlertDialog = new AlertDialog.Builder(mContext)
-            .setTitle(title)
-            .setMessage(message)
-            .setCancelable(false)
-            .setNeutralButton(R.string.ok, null)
-            .create();
+                .setTitle(title)
+                .setMessage(message)
+                .setCancelable(false)
+                .setNeutralButton(R.string.ok, null)
+                .create();
         if (!(mContext instanceof Activity)) {
             mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
         }
@@ -490,6 +655,47 @@
         }
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                MeasureSpec.getSize(widthMeasureSpec) / 2,
+                MeasureSpec.getMode(widthMeasureSpec));
+
+        for (int i = 0; i < getChildCount(); i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() != GONE) {
+                if (mOneHandedMode && isKeyguardSecurityView(view)) {
+                    measureChildWithMargins(view, halfWidthMeasureSpec, 0,
+                            heightMeasureSpec, 0);
+                } else {
+                    measureChildWithMargins(view, widthMeasureSpec, 0,
+                            heightMeasureSpec, 0);
+                }
+                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                maxWidth = Math.max(maxWidth,
+                        view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
+                maxHeight = Math.max(maxHeight,
+                        view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+                childState = combineMeasuredStates(childState, view.getMeasuredState());
+            }
+        }
+
+        maxWidth += getPaddingLeft() + getPaddingRight();
+        maxHeight += getPaddingTop() + getPaddingBottom();
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+    }
+
     void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
         String message = null;
         switch (userType) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 1a8d420..fdab8db 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -404,6 +404,7 @@
         if (newView != null) {
             newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
             mSecurityViewFlipperController.show(newView);
+            mView.updateLayoutForSecurityMode(securityMode);
         }
 
         mSecurityCallback.onSecurityModeChanged(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index c77c867..631c248 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -92,4 +92,13 @@
                 throw new IllegalStateException("Unknown security quality:" + security);
         }
     }
+
+    /**
+     * Returns whether the given security view should be used in a "one handed" way. This can be
+     * used to change how the security view is drawn (e.g. take up less of the screen, and align to
+     * one side).
+     */
+    public static boolean isSecurityViewOneHanded(SecurityMode securityMode) {
+        return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 2373d75..83c2d1e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -405,14 +405,19 @@
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         }
 
+        /**
+         * Set the amount (ratio) that the device has transitioned to doze.
+         *
+         * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
+         */
         public void setDarkAmount(float darkAmount) {
-            boolean isAwake = darkAmount != 0;
-            boolean wasAwake = mDarkAmount != 0;
-            if (isAwake == wasAwake) {
+            boolean isDozing = darkAmount != 0;
+            boolean wasDozing = mDarkAmount != 0;
+            if (isDozing == wasDozing) {
                 return;
             }
             mDarkAmount = darkAmount;
-            setLayoutAnimationListener(isAwake ? null : mKeepAwakeListener);
+            setLayoutAnimationListener(isDozing ? null : mKeepAwakeListener);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fe0ae33..ae4c8e5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -59,6 +59,7 @@
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.screenrecord.RecordingController;
@@ -246,6 +247,7 @@
     @Inject Lazy<KeyguardUpdateMonitor> mKeyguardUpdateMonitor;
     @Inject Lazy<BatteryController> mBatteryController;
     @Inject Lazy<NightDisplayListener> mNightDisplayListener;
+    @Inject Lazy<ReduceBrightColorsController> mReduceBrightColorsController;
     @Inject Lazy<ManagedProfileController> mManagedProfileController;
     @Inject Lazy<NextAlarmController> mNextAlarmController;
     @Inject Lazy<DataSaverController> mDataSaverController;
@@ -393,6 +395,8 @@
 
         mProviders.put(NightDisplayListener.class, mNightDisplayListener::get);
 
+        mProviders.put(ReduceBrightColorsController.class, mReduceBrightColorsController::get);
+
         mProviders.put(ManagedProfileController.class, mManagedProfileController::get);
 
         mProviders.put(NextAlarmController.class, mNextAlarmController::get);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 865ca40..59c0fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -19,15 +19,18 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.TimingsTraceLog;
 import android.view.SurfaceControl;
@@ -37,6 +40,8 @@
 import com.android.systemui.dagger.GlobalRootComponent;
 import com.android.systemui.dagger.SysUIComponent;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.people.PeopleSpaceActivity;
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
 import com.android.systemui.shared.system.ThreadedRendererCompat;
 import com.android.systemui.util.NotificationChannels;
 
@@ -121,6 +126,26 @@
                             mServices[i].onBootCompleted();
                         }
                     }
+                    // If SHOW_PEOPLE_SPACE is true, enable People Space widget provider.
+                    // TODO(b/170396074): Migrate to new feature flag (go/silk-flags-howto)
+                    try {
+                        int showPeopleSpace = Settings.Global.getInt(context.getContentResolver(),
+                                Settings.Global.SHOW_PEOPLE_SPACE, 1);
+                        context.getPackageManager().setComponentEnabledSetting(
+                                new ComponentName(context, PeopleSpaceWidgetProvider.class),
+                                showPeopleSpace == 1
+                                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                                PackageManager.DONT_KILL_APP);
+                        context.getPackageManager().setComponentEnabledSetting(
+                                new ComponentName(context, PeopleSpaceActivity.class),
+                                showPeopleSpace == 1
+                                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                                PackageManager.DONT_KILL_APP);
+                    } catch (Exception e) {
+                        Log.w(TAG, "Error enabling People Space widget:", e);
+                    }
                 }
             }, bootCompletedFilter);
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 19520df..9d00262 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -115,7 +115,8 @@
                     .setShellCommandHandler(mWMComponent.getShellCommandHandler())
                     .setAppPairs(mWMComponent.getAppPairs())
                     .setTaskViewFactory(mWMComponent.getTaskViewFactory())
-                    .setTransitions(mWMComponent.getTransitions());
+                    .setTransitions(mWMComponent.getTransitions())
+                    .setStartingSurface(mWMComponent.getStartingSurface());
         } else {
             // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
             // is separating this logic into newly creating SystemUITestsFactory.
@@ -129,7 +130,8 @@
                     .setShellCommandHandler(Optional.ofNullable(null))
                     .setAppPairs(Optional.ofNullable(null))
                     .setTaskViewFactory(Optional.ofNullable(null))
-                    .setTransitions(Transitions.createEmptyForTesting());
+                    .setTransitions(Transitions.createEmptyForTesting())
+                    .setStartingSurface(Optional.ofNullable(null));
         }
         mSysUIComponent = builder.build();
         if (initializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
index 3bf75d1..a029003 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
@@ -31,15 +31,18 @@
  * sensor area.
  */
 public abstract class UdfpsAnimation extends Drawable {
-    abstract void updateColor();
+    protected abstract void updateColor();
+    protected abstract void onDestroy();
 
     @NonNull protected final Context mContext;
     @NonNull protected final Drawable mFingerprintDrawable;
     @Nullable private View mView;
+    private boolean mIlluminationShowing;
 
     public UdfpsAnimation(@NonNull Context context) {
         mContext = context;
         mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
+        mFingerprintDrawable.mutate();
     }
 
     public void onSensorRectUpdated(@NonNull RectF sensorRect) {
@@ -60,6 +63,14 @@
         mView = view;
     }
 
+    boolean isIlluminationShowing() {
+        return mIlluminationShowing;
+    }
+
+    void setIlluminationShowing(boolean showing) {
+        mIlluminationShowing = showing;
+    }
+
     /**
      * @return The amount of padding that's needed on each side of the sensor, in pixels.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
index 5290986..28b5719 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
@@ -58,11 +58,16 @@
     }
 
     @Override
-    void updateColor() {
+    protected void updateColor() {
         mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
     }
 
     @Override
+    protected void onDestroy() {
+
+    }
+
+    @Override
     public void onSensorRectUpdated(@NonNull RectF sensorRect) {
         super.onSensorRectUpdated(sensorRect);
         mSensorRect = sensorRect;
@@ -70,6 +75,10 @@
 
     @Override
     public void draw(@NonNull Canvas canvas) {
+        if (isIlluminationShowing()) {
+            return;
+        }
+
         final boolean isNightMode = (mContext.getResources().getConfiguration().uiMode
                 & Configuration.UI_MODE_NIGHT_YES) != 0;
         if (!isNightMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
index efc864a..ef7a340 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
@@ -34,12 +34,21 @@
     }
 
     @Override
-    void updateColor() {
+    protected void updateColor() {
+
+    }
+
+    @Override
+    protected void onDestroy() {
 
     }
 
     @Override
     public void draw(@NonNull Canvas canvas) {
+        if (isIlluminationShowing()) {
+            return;
+        }
+
         mFingerprintDrawable.draw(canvas);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
index 8664e44..5f268cf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
@@ -42,6 +42,7 @@
     private static final String TAG = "UdfpsAnimationKeyguard";
 
     @NonNull private final Context mContext;
+    @NonNull private final StatusBarStateController mStatusBarStateController;
     private final int mMaxBurnInOffsetX;
     private final int mMaxBurnInOffsetY;
 
@@ -54,6 +55,7 @@
             @NonNull StatusBarStateController statusBarStateController) {
         super(context);
         mContext = context;
+        mStatusBarStateController = statusBarStateController;
 
         mMaxBurnInOffsetX = context.getResources()
                 .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
@@ -89,6 +91,10 @@
 
     @Override
     public void draw(@NonNull Canvas canvas) {
+        if (isIlluminationShowing()) {
+            return;
+        }
+
         canvas.save();
         canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
         mFingerprintDrawable.draw(canvas);
@@ -106,11 +112,16 @@
     }
 
     @Override
-    public void updateColor() {
+    protected void updateColor() {
         final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
                 R.attr.wallpaperTextColor);
         final int ambientDisplayIconColor = Color.WHITE;
         mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
                 ambientDisplayIconColor, mInterpolatedDarkAmount));
     }
+
+    @Override
+    protected void onDestroy() {
+        mStatusBarStateController.removeCallback(this);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 44122cb..f4dd181 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -22,41 +22,49 @@
 import android.graphics.Canvas;
 import android.graphics.RectF;
 import android.util.AttributeSet;
-import android.view.View;
+import android.widget.FrameLayout;
 
 import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 /**
- * Class that coordinates non-HBM animations (such as enroll, keyguard, BiometricPrompt,
- * FingerprintManager).
+ * Base class for views containing UDFPS animations. Note that this is a FrameLayout so that we
+ * can support multiple child views drawing on the same region around the sensor location.
  */
-public class UdfpsAnimationView extends View implements DozeReceiver,
+public abstract class UdfpsAnimationView extends FrameLayout implements DozeReceiver,
         StatusBar.ExpansionChangedListener {
 
     private static final String TAG = "UdfpsAnimationView";
 
+    @Nullable protected abstract UdfpsAnimation getUdfpsAnimation();
+
     @NonNull private UdfpsView mParent;
-    @Nullable private UdfpsAnimation mUdfpsAnimation;
     @NonNull private RectF mSensorRect;
     private int mAlpha;
 
     public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mSensorRect = new RectF();
+        setWillNotDraw(false);
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
-        if (mUdfpsAnimation != null) {
+        if (getUdfpsAnimation() != null) {
             final int alpha = mParent.shouldPauseAuth() ? mAlpha : 255;
-            mUdfpsAnimation.setAlpha(alpha);
-            mUdfpsAnimation.draw(canvas);
+            getUdfpsAnimation().setAlpha(alpha);
+            getUdfpsAnimation().draw(canvas);
         }
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getUdfpsAnimation().onDestroy();
+    }
+
     private int expansionToAlpha(float expansion) {
         // Fade to 0 opacity when reaching this expansion amount
         final float maxExpansion = 0.4f;
@@ -69,38 +77,38 @@
         return (int) ((1 - percent) * 255);
     }
 
+    void onIlluminationStarting() {
+        getUdfpsAnimation().setIlluminationShowing(true);
+        postInvalidate();
+    }
+
+    void onIlluminationStopped() {
+        getUdfpsAnimation().setIlluminationShowing(false);
+        postInvalidate();
+    }
+
     void setParent(@NonNull UdfpsView parent) {
         mParent = parent;
     }
 
-    void setAnimation(@Nullable UdfpsAnimation animation) {
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.setAnimationView(null);
-        }
-
-        mUdfpsAnimation = animation;
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.setAnimationView(this);
-        }
-    }
-
     void onSensorRectUpdated(@NonNull RectF sensorRect) {
         mSensorRect = sensorRect;
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.onSensorRectUpdated(mSensorRect);
+        if (getUdfpsAnimation() != null) {
+            getUdfpsAnimation().onSensorRectUpdated(mSensorRect);
         }
     }
 
     void updateColor() {
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.updateColor();
+        if (getUdfpsAnimation() != null) {
+            getUdfpsAnimation().updateColor();
         }
+        postInvalidate();
     }
 
     @Override
     public void dozeTimeTick() {
-        if (mUdfpsAnimation instanceof DozeReceiver) {
-            ((DozeReceiver) mUdfpsAnimation).dozeTimeTick();
+        if (getUdfpsAnimation() instanceof DozeReceiver) {
+            ((DozeReceiver) getUdfpsAnimation()).dozeTimeTick();
         }
     }
 
@@ -111,16 +119,16 @@
     }
 
     public int getPaddingX() {
-        if (mUdfpsAnimation == null) {
+        if (getUdfpsAnimation() == null) {
             return 0;
         }
-        return mUdfpsAnimation.getPaddingX();
+        return getUdfpsAnimation().getPaddingX();
     }
 
     public int getPaddingY() {
-        if (mUdfpsAnimation == null) {
+        if (getUdfpsAnimation() == null) {
             return 0;
         }
-        return mUdfpsAnimation.getPaddingY();
+        return getUdfpsAnimation().getPaddingY();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
new file mode 100644
index 0000000..19e77493
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 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.biometrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * Class that coordinates non-HBM animations during enrollment.
+ */
+public class UdfpsAnimationViewEnroll extends UdfpsAnimationView
+        implements UdfpsEnrollHelper.Listener {
+
+    private static final String TAG = "UdfpsAnimationViewEnroll";
+
+    @NonNull private UdfpsAnimation mUdfpsAnimation;
+    @NonNull private UdfpsProgressBar mProgressBar;
+    @Nullable private UdfpsEnrollHelper mEnrollHelper;
+
+    @NonNull
+    @Override
+    protected UdfpsAnimation getUdfpsAnimation() {
+        return mUdfpsAnimation;
+    }
+
+    public UdfpsAnimationViewEnroll(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mUdfpsAnimation = new UdfpsAnimationEnroll(context);
+    }
+
+    public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
+        mEnrollHelper = helper;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mProgressBar = findViewById(R.id.progress_bar);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mEnrollHelper == null) {
+            Log.e(TAG, "Enroll helper is null");
+            return;
+        }
+
+        if (mEnrollHelper.shouldShowProgressBar()) {
+            mProgressBar.setVisibility(View.VISIBLE);
+
+            // Only need enrollment updates if the progress bar is showing :)
+            mEnrollHelper.setListener(this);
+        }
+    }
+
+    @Override
+    public void onEnrollmentProgress(int remaining, int totalSteps) {
+        final int interpolatedProgress = mProgressBar.getMax()
+                * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1);
+
+        mProgressBar.setProgress(interpolatedProgress, true);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
new file mode 100644
index 0000000..3d2f5a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Class that coordinates non-HBM animations during other usage of FingerprintManager (not
+ * including Keyguard).
+ */
+public class UdfpsAnimationViewFpmOther extends UdfpsAnimationView {
+
+    private final UdfpsAnimationFpmOther mAnimation;
+
+    public UdfpsAnimationViewFpmOther(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mAnimation = new UdfpsAnimationFpmOther(context);
+    }
+
+    @Nullable
+    @Override
+    protected UdfpsAnimation getUdfpsAnimation() {
+        return mAnimation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
new file mode 100644
index 0000000..7d0b3e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+
+/**
+ * Class that coordinates non-HBM animations during keyguard authentication.
+ */
+public class UdfpsAnimationViewKeyguard extends UdfpsAnimationView {
+    @Nullable private UdfpsAnimationKeyguard mAnimation;
+
+    public UdfpsAnimationViewKeyguard(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    void setStatusBarStateController(@NonNull StatusBarStateController statusBarStateController) {
+        if (mAnimation == null) {
+            mAnimation = new UdfpsAnimationKeyguard(getContext(), statusBarStateController);
+            mAnimation.setAnimationView(this);
+        }
+    }
+
+    @Nullable
+    @Override
+    protected UdfpsAnimation getUdfpsAnimation() {
+        return mAnimation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 71fba33..e1d7eb3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -71,7 +71,8 @@
     @NonNull private final LayoutInflater mInflater;
     private final WindowManager mWindowManager;
     private final DelayableExecutor mFgExecutor;
-    private final StatusBarStateController mStatusBarStateController;
+    @NonNull private final StatusBar mStatusBar;
+    @NonNull private final StatusBarStateController mStatusBarStateController;
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
     @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -110,18 +111,20 @@
 
         @Override
         public void onEnrollmentProgress(int sensorId, int remaining) {
-            if (mView == null) {
+            if (mEnrollHelper == null) {
+                Log.e(TAG, "onEnrollProgress received but helper is null");
                 return;
             }
-            mView.onEnrollmentProgress(remaining);
+            mEnrollHelper.onEnrollmentProgress(remaining);
         }
 
         @Override
         public void onEnrollmentHelp(int sensorId) {
-            if (mView == null) {
+            if (mEnrollHelper == null) {
+                Log.e(TAG, "onEnrollmentHelp received but helper is null");
                 return;
             }
-            mView.onEnrollmentHelp();
+            mEnrollHelper.onEnrollmentHelp();
         }
 
         @Override
@@ -135,20 +138,14 @@
 
     @VisibleForTesting
     final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
-            (expansion, expanded) -> {
-                if (mView != null) {
-                    mView.onExpansionChanged(expansion, expanded);
-                }
-    };
+            (expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
 
     @VisibleForTesting
     final StatusBarStateController.StateListener mStatusBarStateListener =
             new StatusBarStateController.StateListener() {
                 @Override
                 public void onStateChanged(int newState) {
-                    if (mView != null) {
                         mView.onStateChanged(newState);
-                    }
                 }
     };
 
@@ -189,7 +186,7 @@
             WindowManager windowManager,
             @NonNull StatusBarStateController statusBarStateController,
             @Main DelayableExecutor fgExecutor,
-            @Nullable StatusBar statusBar) {
+            @NonNull StatusBar statusBar) {
         mContext = context;
         mInflater = inflater;
         // The fingerprint manager is queried for UDFPS before this class is constructed, so the
@@ -197,6 +194,7 @@
         mFingerprintManager = checkNotNull(fingerprintManager);
         mWindowManager = windowManager;
         mFgExecutor = fgExecutor;
+        mStatusBar = statusBar;
         mStatusBarStateController = statusBarStateController;
 
         mSensorProps = findFirstUdfps();
@@ -217,9 +215,6 @@
                 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 
-        statusBar.addExpansionChangedListener(mStatusBarExpansionListener);
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
-
         mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
     }
 
@@ -278,7 +273,7 @@
         }
     }
 
-    private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimation animation) {
+    private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimationView animation) {
         final int paddingX = animation != null ? animation.getPaddingX() : 0;
         final int paddingY = animation != null ? animation.getPaddingY() : 0;
 
@@ -330,13 +325,19 @@
             if (mView == null) {
                 try {
                     Log.v(TAG, "showUdfpsOverlay | adding window");
-
+                    // TODO: Eventually we should refactor the code to inflate an
+                    //  operation-specific view here, instead of inflating a generic udfps_view
+                    //  and adding operation-specific animations to it.
                     mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
                     mView.setSensorProperties(mSensorProps);
                     mView.setHbmCallback(this);
 
-                    final UdfpsAnimation animation = getUdfpsAnimationForReason(reason);
-                    mView.setExtras(animation, mEnrollHelper);
+                    final UdfpsAnimationView animation = getUdfpsAnimationViewForReason(reason);
+                    mView.setAnimationView(animation);
+
+                    mStatusBar.addExpansionChangedListener(mStatusBarExpansionListener);
+                    mStatusBarStateController.addCallback(mStatusBarStateListener);
+
                     mWindowManager.addView(mView, computeLayoutParams(animation));
                     mView.setOnTouchListener(mOnTouchListener);
                 } catch (RuntimeException e) {
@@ -348,17 +349,34 @@
         });
     }
 
-    @Nullable
-    private UdfpsAnimation getUdfpsAnimationForReason(int reason) {
+    @NonNull
+    private UdfpsAnimationView getUdfpsAnimationViewForReason(int reason) {
         Log.d(TAG, "getUdfpsAnimationForReason: " + reason);
+
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+
         switch (reason) {
             case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR:
-            case IUdfpsOverlayController.REASON_ENROLL_ENROLLING:
-                return new UdfpsAnimationEnroll(mContext);
-            case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD:
-                return new UdfpsAnimationKeyguard(mContext, mStatusBarStateController);
-            case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER:
-                return new UdfpsAnimationFpmOther(mContext);
+            case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: {
+                final UdfpsAnimationViewEnroll animation = (UdfpsAnimationViewEnroll)
+                        inflater.inflate(R.layout.udfps_animation_view_enroll, null, false);
+                animation.setEnrollHelper(mEnrollHelper);
+                return animation;
+            }
+
+            case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: {
+                final UdfpsAnimationViewKeyguard animation = (UdfpsAnimationViewKeyguard)
+                        inflater.inflate(R.layout.udfps_animation_view_keyguard, null, false);
+                animation.setStatusBarStateController(mStatusBarStateController);
+                return animation;
+            }
+
+            case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: {
+                final UdfpsAnimationViewFpmOther animation = (UdfpsAnimationViewFpmOther)
+                        inflater.inflate(R.layout.udfps_animation_view_fpm_other, null, false);
+                return animation;
+            }
+
             default:
                 Log.d(TAG, "Animation for reason " + reason + " not supported yet");
                 return null;
@@ -371,6 +389,10 @@
                 Log.v(TAG, "hideUdfpsOverlay | removing window");
                 // Reset the controller back to its starting state.
                 onFingerUp();
+
+                mStatusBar.removeExpansionChangedListener(mStatusBarExpansionListener);
+                mStatusBarStateController.removeCallback(mStatusBarStateListener);
+
                 mWindowManager.removeView(mView);
                 mView = null;
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 2442633..942fa7a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -16,22 +16,28 @@
 
 package com.android.systemui.biometrics;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 
-import androidx.annotation.NonNull;
-
 /**
  * Helps keep track of enrollment state and animates the progress bar accordingly.
  */
 public class UdfpsEnrollHelper {
     private static final String TAG = "UdfpsEnrollHelper";
 
+    interface Listener {
+        void onEnrollmentProgress(int remaining, int totalSteps);
+    }
+
     // IUdfpsOverlayController reason
     private final int mEnrollReason;
 
     private int mTotalSteps = -1;
     private int mCurrentProgress = 0;
 
+    @Nullable Listener mListener;
+
     public UdfpsEnrollHelper(int reason) {
         mEnrollReason = reason;
     }
@@ -40,21 +46,29 @@
         return mEnrollReason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING;
     }
 
-    void onEnrollmentProgress(int remaining, @NonNull UdfpsProgressBar progressBar) {
+    void onEnrollmentProgress(int remaining) {
         if (mTotalSteps == -1) {
             mTotalSteps = remaining;
         }
 
-        mCurrentProgress = progressBar.getMax() * Math.max(0, mTotalSteps + 1 - remaining)
-                / (mTotalSteps + 1);
-        progressBar.setProgress(mCurrentProgress, true /* animate */);
-    }
-
-    void updateProgress(@NonNull UdfpsProgressBar progressBar) {
-        progressBar.setProgress(mCurrentProgress);
+        if (mListener != null) {
+            mListener.onEnrollmentProgress(remaining, mTotalSteps);
+        }
     }
 
     void onEnrollmentHelp() {
 
     }
+
+    void setListener(@NonNull Listener listener) {
+        mListener = listener;
+
+        // Only notify during setListener if enrollment is already in progress, so the progress
+        // bar can be updated. If enrollment has not started yet, the progress bar will be empty
+        // anyway.
+        if (mTotalSteps != -1) {
+            final int remainingSteps = mTotalSteps - mCurrentProgress;
+            mListener.onEnrollmentProgress(remainingSteps, mTotalSteps);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
index 97c215e..61ec127 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
@@ -52,6 +52,12 @@
     public UdfpsSurfaceView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
+        // Make this SurfaceView draw on top of everything else in this window. This allows us to
+        // 1) Always show the HBM circle on top of everything else, and
+        // 2) Properly composite this view with any other animations in the same window no matter
+        //    what contents are added in which order to this view hierarchy.
+        setZOrderOnTop(true);
+
         mHolder = getHolder();
         mHolder.setFormat(PixelFormat.RGBA_8888);
 
@@ -61,7 +67,9 @@
         mSensorPaint.setARGB(255, 255, 255, 255);
         mSensorPaint.setStyle(Paint.Style.FILL);
 
-        mIlluminationDotDrawable = canvas -> canvas.drawOval(mSensorRect, mSensorPaint);
+        mIlluminationDotDrawable = canvas -> {
+            canvas.drawOval(mSensorRect, mSensorPaint);
+        };
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 3997943..cd849e6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -32,7 +32,6 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -51,12 +50,11 @@
 
     private static final int DEBUG_TEXT_SIZE_PX = 32;
 
-    @NonNull private final UdfpsSurfaceView mHbmSurfaceView;
-    @NonNull private final UdfpsAnimationView mAnimationView;
     @NonNull private final RectF mSensorRect;
     @NonNull private final Paint mDebugTextPaint;
 
-    @Nullable private UdfpsProgressBar mProgressBar;
+    @NonNull private UdfpsSurfaceView mHbmSurfaceView;
+    @Nullable private UdfpsAnimationView mAnimationView;
 
     // Used to obtain the sensor location.
     @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -66,7 +64,6 @@
     private boolean mIlluminationRequested;
     private int mStatusBarState;
     private boolean mNotificationShadeExpanded;
-    @Nullable private UdfpsEnrollHelper mEnrollHelper;
 
     public UdfpsView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -84,19 +81,6 @@
             a.recycle();
         }
 
-        // Inflate UdfpsSurfaceView
-        final LayoutInflater inflater = LayoutInflater.from(context);
-        mHbmSurfaceView = (UdfpsSurfaceView) inflater.inflate(R.layout.udfps_surface_view,
-                null, false);
-        addView(mHbmSurfaceView);
-        mHbmSurfaceView.setVisibility(View.INVISIBLE);
-
-        // Inflate UdfpsAnimationView
-        mAnimationView = (UdfpsAnimationView) inflater.inflate(R.layout.udfps_animation_view,
-                null, false);
-        mAnimationView.setParent(this);
-        addView(mAnimationView);
-
         mSensorRect = new RectF();
 
         mDebugTextPaint = new Paint();
@@ -107,22 +91,22 @@
         mIlluminationRequested = false;
     }
 
+    @Override
+    protected void onFinishInflate() {
+        mHbmSurfaceView = findViewById(R.id.hbm_view);
+    }
+
     void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
         mSensorProps = properties;
     }
 
-    void setExtras(@Nullable UdfpsAnimation animation, @Nullable UdfpsEnrollHelper enrollHelper) {
-        mAnimationView.setAnimation(animation);
+    void setAnimationView(@NonNull UdfpsAnimationView animation) {
+        mAnimationView = animation;
+        animation.setParent(this);
 
-        mEnrollHelper = enrollHelper;
-
-        if (enrollHelper != null) {
-            mEnrollHelper.updateProgress(mProgressBar);
-            mProgressBar.setVisibility(enrollHelper.shouldShowProgressBar()
-                    ? View.VISIBLE : View.GONE);
-        } else {
-            mProgressBar.setVisibility(View.GONE);
-        }
+        // TODO: Consider using a ViewStub placeholder to maintain positioning and inflating it
+        //  after the animation type has been decided.
+        addView(animation, 0);
     }
 
     @Override
@@ -132,6 +116,9 @@
 
     @Override
     public void dozeTimeTick() {
+        if (mAnimationView == null) {
+            return;
+        }
         mAnimationView.dozeTimeTick();
     }
 
@@ -143,12 +130,10 @@
     @Override
     public void onExpansionChanged(float expansion, boolean expanded) {
         mNotificationShadeExpanded = expanded;
-        mAnimationView.onExpansionChanged(expansion, expanded);
-    }
 
-    @Override
-    protected void onFinishInflate() {
-        mProgressBar = findViewById(R.id.progress_bar);
+        if (mAnimationView != null) {
+            mAnimationView.onExpansionChanged(expansion, expanded);
+        }
     }
 
     @Override
@@ -229,7 +214,7 @@
     @Override
     public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
         mIlluminationRequested = true;
-        mAnimationView.setVisibility(View.INVISIBLE);
+        mAnimationView.onIlluminationStarting();
         mHbmSurfaceView.setVisibility(View.VISIBLE);
         mHbmSurfaceView.startIllumination(onIlluminatedRunnable);
     }
@@ -237,16 +222,8 @@
     @Override
     public void stopIllumination() {
         mIlluminationRequested = false;
-        mAnimationView.setVisibility(View.VISIBLE);
+        mAnimationView.onIlluminationStopped();
         mHbmSurfaceView.setVisibility(View.INVISIBLE);
         mHbmSurfaceView.stopIllumination();
     }
-
-    void onEnrollmentProgress(int remaining) {
-        mEnrollHelper.onEnrollmentProgress(remaining, mProgressBar);
-    }
-
-    void onEnrollmentHelp() {
-
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 726e2d0..a2f96bb 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -25,6 +25,7 @@
 import android.content.SharedPreferences;
 import android.content.om.OverlayManager;
 import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.ColorDisplayManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -60,6 +61,7 @@
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.settings.UserTracker;
@@ -82,6 +84,7 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.theme.ThemeOverlayApplier;
 import com.android.systemui.util.leak.LeakDetector;
+import com.android.systemui.util.settings.SecureSettings;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.pip.Pip;
 
@@ -266,6 +269,15 @@
     }
 
     /** */
+    @SysUISingleton
+    @Provides
+    public ReduceBrightColorsController provideReduceBrightColorsListener(
+            @Background Handler bgHandler, UserTracker userTracker,
+            ColorDisplayManager colorDisplayManager, SecureSettings secureSettings) {
+        return new ReduceBrightColorsController(userTracker, bgHandler,
+                colorDisplayManager, secureSettings);
+    }
+
     @Provides
     @SysUISingleton
     public ActivityManagerWrapper provideActivityManagerWrapper() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index ffb8446..8f79de5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -33,6 +33,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.transition.RemoteTransitions;
 
 import java.util.Optional;
@@ -88,6 +89,9 @@
         @BindsInstance
         Builder setTransitions(RemoteTransitions t);
 
+        @BindsInstance
+        Builder setStartingSurface(Optional<StartingSurface> s);
+
         SysUIComponent build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 5d226d5..1ed8819 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -27,7 +27,6 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
 import com.android.systemui.media.systemsounds.HomeSoundEffectController;
-import com.android.systemui.people.widget.PeopleSpaceWidgetEnabler;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.television.TvOngoingPrivacyChip;
 import com.android.systemui.recents.Recents;
@@ -185,10 +184,4 @@
     @IntoMap
     @ClassKey(HomeSoundEffectController.class)
     public abstract SystemUI bindHomeSoundEffectController(HomeSoundEffectController sysui);
-
-    /** Inject into PeopleSpaceWidgetEnabler. */
-    @Binds
-    @IntoMap
-    @ClassKey(PeopleSpaceWidgetEnabler.class)
-    public abstract SystemUI bindPeopleSpaceWidgetEnabler(PeopleSpaceWidgetEnabler sysui);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index f3726a3..1b77d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -32,6 +32,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.transition.RemoteTransitions;
 
 import java.util.Optional;
@@ -98,4 +99,7 @@
 
     @WMSingleton
     RemoteTransitions getTransitions();
+
+    @WMSingleton
+    Optional<StartingSurface> getStartingSurface();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 19e3278..35d5ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -279,9 +279,11 @@
             return;
         }
 
+        // When in gestural and the IME is showing, don't use the nearest region since it will take
+        // gesture space away from the IME
         info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
         info.touchableRegion.set(getButtonLocations(false /* includeFloatingRotationButton */,
-                false /* inScreen */));
+                false /* inScreen */, false /* useNearestRegion */));
     };
 
     private final Consumer<Boolean> mRotationButtonListener = (visible) -> {
@@ -981,7 +983,8 @@
      */
     public void notifyActiveTouchRegions() {
         mOverviewProxyService.onActiveNavBarRegionChanges(
-                getButtonLocations(true /* includeFloatingRotationButton */, true /* inScreen */));
+                getButtonLocations(true /* includeFloatingRotationButton */, true /* inScreen */,
+                        true /* useNearestRegion */));
     }
 
     private void updateButtonTouchRegionCache() {
@@ -992,35 +995,49 @@
                 .findViewById(R.id.nav_buttons)).getFullTouchableChildRegions();
     }
 
+    /**
+     * @param includeFloatingRotationButton Whether to include the floating rotation button in the
+     *                                      region for all the buttons
+     * @param inScreenSpace Whether to return values in screen space or window space
+     * @param useNearestRegion Whether to use the nearest region instead of the actual button bounds
+     * @return
+     */
     private Region getButtonLocations(boolean includeFloatingRotationButton,
-            boolean inScreenSpace) {
+            boolean inScreenSpace, boolean useNearestRegion) {
+        if (useNearestRegion && !inScreenSpace) {
+            // We currently don't support getting the nearest region in anything but screen space
+            useNearestRegion = false;
+        }
         mTmpRegion.setEmpty();
         updateButtonTouchRegionCache();
-        updateButtonLocation(getBackButton(), inScreenSpace);
-        updateButtonLocation(getHomeButton(), inScreenSpace);
-        updateButtonLocation(getRecentsButton(), inScreenSpace);
-        updateButtonLocation(getImeSwitchButton(), inScreenSpace);
-        updateButtonLocation(getAccessibilityButton(), inScreenSpace);
+        updateButtonLocation(getBackButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getHomeButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getRecentsButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getImeSwitchButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getAccessibilityButton(), inScreenSpace, useNearestRegion);
         if (includeFloatingRotationButton && mFloatingRotationButton.isVisible()) {
+            // Note: this button is floating so the nearest region doesn't apply
             updateButtonLocation(mFloatingRotationButton.getCurrentView(), inScreenSpace);
         } else {
-            updateButtonLocation(getRotateSuggestionButton(), inScreenSpace);
+            updateButtonLocation(getRotateSuggestionButton(), inScreenSpace, useNearestRegion);
         }
         if (mNavBarOverlayController.isNavigationBarOverlayEnabled()
                 && mNavBarOverlayController.isVisible()) {
+            // Note: this button is floating so the nearest region doesn't apply
             updateButtonLocation(mNavBarOverlayController.getCurrentView(), inScreenSpace);
         }
         return mTmpRegion;
     }
 
-    private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace) {
+    private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace,
+            boolean useNearestRegion) {
         View view = button.getCurrentView();
         if (view == null || !button.isVisible()) {
             return;
         }
         // If the button is tappable from perspective of NearestTouchFrame, then we'll
         // include the regions where the tap is valid instead of just the button layout location
-        if (mButtonFullTouchableRegions.containsKey(view)) {
+        if (useNearestRegion && mButtonFullTouchableRegions.containsKey(view)) {
             mTmpRegion.op(mButtonFullTouchableRegions.get(view), Op.UNION);
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 870e3be..422ffd5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -200,7 +200,7 @@
         Log.d(TAG, "  assetPaths=");
         ApkAssets[] assets = context.getResources().getAssets().getApkAssets();
         for (ApkAssets a : assets) {
-            Log.d(TAG, "    " + a.getAssetPath());
+            Log.d(TAG, "    " + a.getDebugName());
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
deleted file mode 100644
index 3df2644..0000000
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2021 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.people.widget;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.util.Log;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.people.PeopleSpaceActivity;
-import com.android.systemui.statusbar.FeatureFlags;
-
-import javax.inject.Inject;
-
-/**
- * Enables People Space widgets.
- */
-@SysUISingleton
-public class PeopleSpaceWidgetEnabler extends SystemUI {
-    private static final String TAG = "PeopleSpaceWdgtEnabler";
-    private Context mContext;
-    private FeatureFlags mFeatureFlags;
-
-    @Inject
-    public PeopleSpaceWidgetEnabler(Context context, FeatureFlags featureFlags) {
-        super(context);
-        mContext = context;
-        mFeatureFlags = featureFlags;
-    }
-
-    @Override
-    public void start() {
-        Log.d(TAG, "Starting service");
-        try {
-            boolean showPeopleSpace = mFeatureFlags.isPeopleTileEnabled();
-            mContext.getPackageManager().setComponentEnabledSetting(
-                    new ComponentName(mContext, PeopleSpaceWidgetProvider.class),
-                    showPeopleSpace
-                            ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
-                            : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                    PackageManager.DONT_KILL_APP);
-            mContext.getPackageManager().setComponentEnabledSetting(
-                    new ComponentName(mContext, PeopleSpaceActivity.class),
-                    showPeopleSpace
-                            ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
-                            : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                    PackageManager.DONT_KILL_APP);
-        } catch (Exception e) {
-            Log.w(TAG, "Error enabling People Space widget:", e);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index 680a617..8ec9b68 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -47,7 +47,7 @@
     context: Context,
     private val list: List<PrivacyElement>,
     activityStarter: (String, Int) -> Unit
-) : SystemUIDialog(context, R.style.ScreenRecord) {
+) : SystemUIDialog(context, R.style.PrivacyDialog) {
 
     private val dismissListeners = mutableListOf<WeakReference<OnDialogDismissed>>()
     private val dismissed = AtomicBoolean(false)
@@ -64,6 +64,7 @@
         super.onCreate(savedInstanceState)
         window?.apply {
             attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
+            attributes.receiveInsetsIgnoringZOrder = true
             setLayout(context.resources.getDimensionPixelSize(R.dimen.qs_panel_width), WRAP_CONTENT)
             setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
new file mode 100644
index 0000000..42d603e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.display.ColorDisplayManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
+/**
+ * @hide
+ */
+public class ReduceBrightColorsController implements
+        CallbackController<ReduceBrightColorsController.Listener> {
+    private final ColorDisplayManager mManager;
+    private final UserTracker mUserTracker;
+    private UserTracker.Callback mCurrentUserTrackerCallback;
+    private final Handler mHandler;
+    private final ContentObserver mContentObserver;
+    private final SecureSettings mSecureSettings;
+    private final ArrayList<ReduceBrightColorsController.Listener> mListeners = new ArrayList<>();
+
+    @Inject
+    public ReduceBrightColorsController(UserTracker userTracker,
+            @Background Handler handler,
+            ColorDisplayManager colorDisplayManager,
+            SecureSettings secureSettings) {
+        mManager = colorDisplayManager;
+        mUserTracker = userTracker;
+        mHandler = handler;
+        mSecureSettings = secureSettings;
+        mContentObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                super.onChange(selfChange, uri);
+                final String setting = uri == null ? null : uri.getLastPathSegment();
+                synchronized (mListeners) {
+                    if (setting != null && mListeners.size() != 0) {
+                        if (setting.equals(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED)) {
+                            for (Listener listener : mListeners) {
+                                listener.onActivated(mManager.isReduceBrightColorsActivated());
+                            }
+                        }
+                    }
+                }
+            }
+        };
+
+        mCurrentUserTrackerCallback = new UserTracker.Callback() {
+            @Override
+            public void onUserChanged(int newUser, Context userContext) {
+                synchronized (mListeners) {
+                    if (mListeners.size() > 0) {
+                        mSecureSettings.unregisterContentObserver(mContentObserver);
+                        mSecureSettings.registerContentObserverForUser(
+                                Settings.Secure.getUriFor(
+                                        Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+                                false, mContentObserver, newUser);
+                    }
+                }
+            }
+        };
+        mUserTracker.addCallback(mCurrentUserTrackerCallback, new HandlerExecutor(handler));
+    }
+
+    @Override
+    public void addCallback(@NonNull Listener listener) {
+        synchronized (mListeners) {
+            if (!mListeners.contains(listener)) {
+                mListeners.add(listener);
+                if (mListeners.size() == 1) {
+                    mSecureSettings.registerContentObserverForUser(
+                            Settings.Secure.getUriFor(
+                                    Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+                            false, mContentObserver, mUserTracker.getUserId());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void removeCallback(@androidx.annotation.NonNull Listener listener) {
+        synchronized (mListeners) {
+            if (mListeners.remove(listener) && mListeners.size() == 0) {
+                mSecureSettings.unregisterContentObserver(mContentObserver);
+            }
+        }
+    }
+
+    /** Returns {@code true} if Reduce Bright Colors is activated */
+    public boolean isReduceBrightColorsActivated() {
+        return mManager.isReduceBrightColorsActivated();
+    }
+
+    /** Sets the activation state of Reduce Bright Colors */
+    public void setReduceBrightColorsActivated(boolean activated) {
+        mManager.setReduceBrightColorsActivated(activated);
+    }
+
+    /**
+     * Listener invoked whenever the Reduce Bright Colors settings are changed.
+     */
+    public interface Listener {
+        /**
+         * Listener invoked when the activated state changes.
+         *
+         * @param activated {@code true} if Reduce Bright Colors is activated.
+         */
+        default void onActivated(boolean activated) {
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index c3cc3af..52f111e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.util.AttributeSet
-import com.android.systemui.R
 
 open class SideLabelTileLayout(
     context: Context,
@@ -28,9 +27,6 @@
     override fun updateResources(): Boolean {
         return super.updateResources().also {
             mMaxAllowedRows = 4
-            mCellMarginHorizontal = (mCellMarginHorizontal * 1.2).toInt()
-            mCellMarginVertical = mCellMarginHorizontal
-            mMaxCellHeight = context.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 47cb45b..ce8f6c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -16,19 +16,19 @@
 
 import android.content.Context;
 import android.view.View;
-import android.widget.TextView;
 
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.tileimpl.QSTileView;
 
-public class CustomizeTileView extends QSTileView {
+public class CustomizeTileView extends QSTileView implements TileAdapter.CustomizeView {
     private boolean mShowAppLabel;
 
     public CustomizeTileView(Context context, QSIconView icon) {
         super(context, icon);
     }
 
+    @Override
     public void setShowAppLabel(boolean showAppLabel) {
         mShowAppLabel = showAppLabel;
         mSecondLine.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
@@ -41,10 +41,6 @@
         mSecondLine.setVisibility(mShowAppLabel ? View.VISIBLE : View.GONE);
     }
 
-    public TextView getAppLabel() {
-        return mSecondLine;
-    }
-
     @Override
     protected boolean animationsEnabled() {
         return false;
@@ -54,4 +50,9 @@
     public boolean isLongClickable() {
         return false;
     }
+
+    @Override
+    public void changeState(QSTile.State state) {
+        handleStateChanged(state);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
new file mode 100644
index 0000000..4ffcd8c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
@@ -0,0 +1,50 @@
+package com.android.systemui.qs.customize
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.view.View
+import com.android.systemui.plugins.qs.QSIconView
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.QSTileViewHorizontal
+
+/**
+ * Class for displaying tiles in [QSCustomizer] with the new design (labels on the side).
+ *
+ * This is a class parallel to [CustomizeTileView], but inheriting from [QSTileViewHorizontal].
+ */
+class CustomizeTileViewHorizontal(
+    context: Context,
+    icon: QSIconView
+) : QSTileViewHorizontal(context, icon),
+    TileAdapter.CustomizeView {
+
+    private var showAppLabel = false
+
+    override fun setShowAppLabel(showAppLabel: Boolean) {
+        this.showAppLabel = showAppLabel
+        mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
+        mLabel.isSingleLine = showAppLabel
+    }
+
+    override fun handleStateChanged(state: QSTile.State) {
+        super.handleStateChanged(state)
+        mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
+    }
+
+    override fun animationsEnabled(): Boolean {
+        return false
+    }
+
+    override fun isLongClickable(): Boolean {
+        return false
+    }
+
+    override fun changeState(state: QSTile.State) {
+        handleStateChanged(state)
+    }
+
+    override fun newTileBackground(): Drawable? {
+        super.newTileBackground()
+        return paintDrawable
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 7a91421..0adc844 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.qs.customize;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,6 +32,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.view.AccessibilityDelegateCompat;
 import androidx.core.view.ViewCompat;
 import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
@@ -41,6 +44,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSEditEvent;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.customize.TileAdapter.Holder;
@@ -49,11 +53,13 @@
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.tileimpl.QSIconViewImpl;
+import com.android.systemui.qs.tileimpl.QSTileView;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /** */
 @QSScope
@@ -75,7 +81,7 @@
     private static final int ACTION_ADD = 1;
     private static final int ACTION_MOVE = 2;
 
-    private static final int NUM_COLUMNS_ID = R.integer.quick_settings_edit_num_columns;
+    private static final int NUM_COLUMNS_ID = R.integer.quick_settings_num_columns;
 
     private final Context mContext;
 
@@ -102,9 +108,11 @@
     private final AccessibilityDelegateCompat mAccessibilityDelegate;
     private RecyclerView mRecyclerView;
     private int mNumColumns;
+    private final boolean mUseHorizontalTiles;
 
     @Inject
-    public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger) {
+    public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger,
+            @Named(QS_LABELS_FLAG) boolean useHorizontalTiles) {
         mContext = context;
         mHost = qsHost;
         mUiEventLogger = uiEventLogger;
@@ -114,6 +122,7 @@
         mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
         mNumColumns = context.getResources().getInteger(NUM_COLUMNS_ID);
         mAccessibilityDelegate = new TileAdapterDelegate();
+        mUseHorizontalTiles = useHorizontalTiles;
     }
 
     @Override
@@ -271,7 +280,10 @@
         }
         FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
                 false);
-        frame.addView(new CustomizeTileView(context, new QSIconViewImpl(context)));
+        View view = mUseHorizontalTiles
+                ? new CustomizeTileViewHorizontal(context, new QSIconViewImpl(context))
+                : new CustomizeTileView(context, new QSIconViewImpl(context));
+        frame.addView(view);
         return new Holder(frame);
     }
 
@@ -354,8 +366,9 @@
         }
         info.state.expandedAccessibilityClassName = "";
 
-        holder.mTileView.handleStateChanged(info.state);
-        holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
+        // The holder has a tileView, therefore this call is not null
+        holder.getTileAsCustomizeView().changeState(info.state);
+        holder.getTileAsCustomizeView().setShowAppLabel(position > mEditIndex && !info.isSystem);
         holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         holder.mTileView.setClickable(true);
         holder.mTileView.setOnClickListener(null);
@@ -534,25 +547,34 @@
     }
 
     public class Holder extends ViewHolder {
-        private CustomizeTileView mTileView;
+        private QSTileView mTileView;
 
         public Holder(View itemView) {
             super(itemView);
             if (itemView instanceof FrameLayout) {
-                mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
-                mTileView.setBackground(null);
+                mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+                if (mTileView instanceof CustomizeTileView) {
+                    mTileView.setBackground(null);
+                }
                 mTileView.getIcon().disableAnimation();
                 mTileView.setTag(this);
                 ViewCompat.setAccessibilityDelegate(mTileView, mAccessibilityDelegate);
             }
         }
 
+        @Nullable
+        public CustomizeView getTileAsCustomizeView() {
+            return (CustomizeView) mTileView;
+        }
+
         public void clearDrag() {
             itemView.clearAnimation();
-            mTileView.findViewById(R.id.tile_label).clearAnimation();
-            mTileView.findViewById(R.id.tile_label).setAlpha(1);
-            mTileView.getAppLabel().clearAnimation();
-            mTileView.getAppLabel().setAlpha(.6f);
+            if (mTileView instanceof CustomizeTileView) {
+                mTileView.findViewById(R.id.tile_label).clearAnimation();
+                mTileView.findViewById(R.id.tile_label).setAlpha(1);
+                mTileView.getAppLabel().clearAnimation();
+                mTileView.getAppLabel().setAlpha(.6f);
+            }
         }
 
         public void startDrag() {
@@ -560,12 +582,14 @@
                     .setDuration(DRAG_LENGTH)
                     .scaleX(DRAG_SCALE)
                     .scaleY(DRAG_SCALE);
-            mTileView.findViewById(R.id.tile_label).animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(0);
-            mTileView.getAppLabel().animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(0);
+            if (mTileView instanceof CustomizeTileView) {
+                mTileView.findViewById(R.id.tile_label).animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(0);
+                mTileView.getAppLabel().animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(0);
+            }
         }
 
         public void stopDrag() {
@@ -573,12 +597,14 @@
                     .setDuration(DRAG_LENGTH)
                     .scaleX(1)
                     .scaleY(1);
-            mTileView.findViewById(R.id.tile_label).animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(1);
-            mTileView.getAppLabel().animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(.6f);
+            if (mTileView instanceof CustomizeTileView) {
+                mTileView.findViewById(R.id.tile_label).animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(1);
+                mTileView.getAppLabel().animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(.6f);
+            }
         }
 
         boolean canRemove() {
@@ -722,7 +748,7 @@
                 int position = mCurrentDrag.getAdapterPosition();
                 if (position == RecyclerView.NO_POSITION) return;
                 TileInfo info = mTiles.get(position);
-                mCurrentDrag.mTileView.setShowAppLabel(
+                ((CustomizeView) mCurrentDrag.mTileView).setShowAppLabel(
                         position > mEditIndex && !info.isSystem);
                 mCurrentDrag.stopDrag();
                 mCurrentDrag = null;
@@ -782,4 +808,9 @@
         public void onSwiped(ViewHolder viewHolder, int direction) {
         }
     };
+
+    interface CustomizeView {
+        void setShowAppLabel(boolean showAppLabel);
+        void changeState(@NonNull QSTile.State state);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 33713f3..d41bd7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.dagger;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
 import android.content.Context;
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
@@ -25,6 +27,7 @@
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -32,6 +35,8 @@
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.util.settings.SecureSettings;
 
+import javax.inject.Named;
+
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
@@ -54,7 +59,9 @@
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
             NightDisplayListener nightDisplayListener,
-            CastController castController) {
+            CastController castController,
+            ReduceBrightColorsController reduceBrightColorsController,
+            @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
         AutoTileManager manager = new AutoTileManager(
                 context,
                 autoAddTrackerBuilder,
@@ -65,7 +72,9 @@
                 dataSaverController,
                 managedProfileController,
                 nightDisplayListener,
-                castController
+                castController,
+                reduceBrightColorsController,
+                isReduceBrightColorsAvailable
         );
         manager.init();
         return manager;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 38e2ba4..33ca7d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -259,23 +259,30 @@
         mIcon.setIcon(state, allowAnimations);
         setContentDescription(state.contentDescription);
         final StringBuilder stateDescription = new StringBuilder();
+        String text = "";
         switch (state.state) {
             case Tile.STATE_UNAVAILABLE:
-                stateDescription.append(mContext.getString(R.string.tile_unavailable));
+                text = mContext.getString(R.string.tile_unavailable);
                 break;
             case Tile.STATE_INACTIVE:
                 if (state instanceof QSTile.BooleanState) {
-                    stateDescription.append(mContext.getString(R.string.switch_bar_off));
+                    text = mContext.getString(R.string.switch_bar_off);
                 }
                 break;
             case Tile.STATE_ACTIVE:
                 if (state instanceof QSTile.BooleanState) {
-                    stateDescription.append(mContext.getString(R.string.switch_bar_on));
+                    text = mContext.getString(R.string.switch_bar_on);
                 }
                 break;
             default:
                 break;
         }
+        if (!TextUtils.isEmpty(text)) {
+            stateDescription.append(text);
+            if (TextUtils.isEmpty(state.secondaryLabel)) {
+                state.secondaryLabel = text;
+            }
+        }
         if (!TextUtils.isEmpty(state.stateDescription)) {
             stateDescription.append(", ");
             stateDescription.append(state.stateDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 207b25d0..b59326a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -174,4 +174,8 @@
         mLabelContainer.setClickable(false);
         mLabelContainer.setLongClickable(false);
     }
+
+    public TextView getAppLabel() {
+        return mSecondLine;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 07d48f3..231037f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -35,13 +35,13 @@
 // Placeholder
 private const val CORNER_RADIUS = 40f
 
-class QSTileViewHorizontal(
+open class QSTileViewHorizontal(
     context: Context,
     icon: QSIconView
 ) : QSTileView(context, icon, false) {
 
-    private var paintDrawable: PaintDrawable? = null
-    private var paintColor = Color.TRANSPARENT
+    protected var paintDrawable: PaintDrawable? = null
+    private var paintColor = Color.WHITE
     private var paintAnimator: ValueAnimator? = null
 
     init {
@@ -103,7 +103,7 @@
         mSecondLine.setTextColor(mLabel.textColors)
         mLabelContainer.background = null
 
-        val allowAnimations = animationsEnabled() && paintColor != Color.TRANSPARENT
+        val allowAnimations = animationsEnabled() && paintColor != Color.WHITE
         val newColor = getCircleColor(state.state)
         if (allowAnimations) {
             animateToNewState(newColor)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index f94cabc..aec7b9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -33,46 +33,39 @@
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.settings.SecureSettings;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
 /** Quick settings tile: Reduce Bright Colors **/
-public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
+public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
+        implements ReduceBrightColorsController.Listener{
 
     //TODO(b/170973645): get icon drawable
     private final Icon mIcon = null;
-    private final SecureSetting mActivatedSetting;
     private final boolean mIsAvailable;
+    private final ReduceBrightColorsController mReduceBrightColorsController;
+    private boolean mIsListening;
 
     @Inject
     public ReduceBrightColorsTile(
             @Named(RBC_AVAILABLE) boolean isAvailable,
+            ReduceBrightColorsController reduceBrightColorsController,
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
-            QSLogger qsLogger,
-            UserTracker userTracker,
-            SecureSettings secureSettings
+            QSLogger qsLogger
     ) {
         super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
                 activityStarter, qsLogger);
-
-        mActivatedSetting = new SecureSetting(secureSettings, mainHandler,
-                Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, userTracker.getUserId()) {
-            @Override
-            protected void handleValueChanged(int value, boolean observedChange) {
-                refreshState();
-            }
-        };
+        mReduceBrightColorsController = reduceBrightColorsController;
+        mReduceBrightColorsController.observe(getLifecycle(), this);
         mIsAvailable = isAvailable;
 
     }
@@ -84,7 +77,6 @@
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
-        mActivatedSetting.setListening(false);
     }
 
     @Override
@@ -93,25 +85,13 @@
     }
 
     @Override
-    public void handleSetListening(boolean listening) {
-        super.handleSetListening(listening);
-        mActivatedSetting.setListening(listening);
-    }
-
-    @Override
-    protected void handleUserSwitch(int newUserId) {
-        mActivatedSetting.setUserId(newUserId);
-        refreshState();
-    }
-
-    @Override
     public Intent getLongClickIntent() {
         return new Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS);
     }
 
     @Override
     protected void handleClick() {
-        mActivatedSetting.setValue(mState.value ? 0 : 1);
+        mReduceBrightColorsController.setReduceBrightColorsActivated(!mState.value);
     }
 
     @Override
@@ -121,7 +101,7 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        state.value = mActivatedSetting.getValue() == 1;
+        state.value = mReduceBrightColorsController.isReduceBrightColorsActivated();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
         state.expandedAccessibilityClassName = Switch.class.getName();
@@ -132,4 +112,9 @@
     public int getMetricsCategory() {
         return 0;
     }
+
+    @Override
+    public void onActivated(boolean activated) {
+        refreshState();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index 53d9f1c..c066619 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -65,6 +65,9 @@
     private float mTopDelta = 0f;
     private float mBottomDelta = 0f;
 
+    private int mExtraTopPadding;
+    private int mExtraBottomPadding;
+
     private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
     private float mStartingY;  // y coordinate of ACTION_DOWN
     private CropInteractionListener mCropInteractionListener;
@@ -117,12 +120,13 @@
                 if (mCurrentDraggingBoundary != CropBoundary.NONE) {
                     float delta = event.getY() - mStartingY;
                     if (mCurrentDraggingBoundary == CropBoundary.TOP) {
-                        mTopDelta = pixelsToFraction((int) MathUtils.constrain(delta, -topPx,
+                        mTopDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta,
+                                -topPx + mExtraTopPadding,
                                 bottomPx - 2 * mCropTouchMargin - topPx));
                     } else {  // Bottom
-                        mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta,
+                        mBottomDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta,
                                 topPx + 2 * mCropTouchMargin - bottomPx,
-                                getHeight() - bottomPx));
+                                getHeight() - bottomPx - mExtraBottomPadding));
                     }
                     updateListener(event);
                     invalidate();
@@ -140,6 +144,25 @@
     }
 
     /**
+     * Set the given boundary to the given value without animation.
+     */
+    public void setBoundaryTo(CropBoundary boundary, float value) {
+        switch (boundary) {
+            case TOP:
+                mTopCrop = value;
+                break;
+            case BOTTOM:
+                mBottomCrop = value;
+                break;
+            case NONE:
+                Log.w(TAG, "No boundary selected for animation");
+                break;
+        }
+
+        invalidate();
+    }
+
+    /**
      * Animate the given boundary to the given value.
      */
     public void animateBoundaryTo(CropBoundary boundary, float value) {
@@ -176,6 +199,16 @@
     }
 
     /**
+     * Set additional top and bottom padding for the image being cropped (used when the
+     * corresponding ImageView doesn't take the full height).
+     */
+    public void setExtraPadding(int top, int bottom) {
+        mExtraTopPadding = top;
+        mExtraBottomPadding = bottom;
+        invalidate();
+    }
+
+    /**
      * @return value [0,1] representing the position of the top crop boundary. Does not reflect
      * changes from any in-progress touch input.
      */
@@ -225,12 +258,22 @@
                 true, mHandlePaint);
     }
 
+    /**
+     * Convert the given fraction position to pixel position within the View.
+     */
     private int fractionToPixels(float frac) {
-        return (int) (frac * getHeight());
+        return (int) (mExtraTopPadding + frac * getImageHeight());
     }
 
-    private float pixelsToFraction(int px) {
-        return px / (float) getHeight();
+    private int getImageHeight() {
+        return getHeight() - mExtraTopPadding - mExtraBottomPadding;
+    }
+
+    /**
+     * Convert the given pixel distance to fraction of the image.
+     */
+    private float pixelDistanceToFraction(int px) {
+        return px / (float) getImageHeight();
     }
 
     private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 89efda9..4dc846e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -20,8 +20,17 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.HardwareRenderer;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -33,6 +42,14 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.time.ZonedDateTime;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
@@ -44,9 +61,21 @@
 public class LongScreenshotActivity extends Activity {
     private static final String TAG = "LongScreenshotActivity";
 
+    private static final String IMAGE_PATH_KEY = "saved-image";
+    private static final String TOP_BOUNDARY_KEY = "top-boundary";
+    private static final String BOTTOM_BOUNDARY_KEY = "bottom-boundary";
+
     private final UiEventLogger mUiEventLogger;
     private final ScrollCaptureController mScrollCaptureController;
     private final ScrollCaptureClient.Connection mConnection;
+    private final Executor mUiExecutor;
+    private final Executor mBackgroundExecutor;
+    private final ImageExporter mImageExporter;
+
+    private String mSavedImagePath;
+    // If true, the activity is re-loading an image from storage, which should either succeed and
+    // populate the UI or fail and finish the activity.
+    private boolean mRestoringInstance;
 
     private ImageView mPreview;
     private View mSave;
@@ -69,6 +98,9 @@
             @Background Executor bgExecutor,
             Context context) {
         mUiEventLogger = uiEventLogger;
+        mUiExecutor = mainExecutor;
+        mBackgroundExecutor = bgExecutor;
+        mImageExporter = imageExporter;
 
         mScrollCaptureController = new ScrollCaptureController(context, mainExecutor, bgExecutor,
                 imageExporter);
@@ -95,12 +127,45 @@
         mCancel.setOnClickListener(this::onClicked);
         mEdit.setOnClickListener(this::onClicked);
         mShare.setOnClickListener(this::onClicked);
+
+        if (savedInstanceState != null) {
+            String imagePath = savedInstanceState.getString(IMAGE_PATH_KEY);
+            if (!TextUtils.isEmpty(imagePath)) {
+                mRestoringInstance = true;
+                mBackgroundExecutor.execute(() -> {
+                    Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
+                    if (bitmap == null) {
+                        Log.e(TAG, "Failed to read bitmap from " + imagePath);
+                        finishAndRemoveTask();
+                    } else {
+                        runOnUiThread(() -> {
+                            BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
+                            mPreview.setImageDrawable(drawable);
+                            mMagnifierView.setDrawable(drawable, bitmap.getWidth(),
+                                    bitmap.getHeight());
+
+                            mCropView.setBoundaryTo(CropView.CropBoundary.TOP,
+                                    savedInstanceState.getFloat(TOP_BOUNDARY_KEY, 0f));
+                            mCropView.setBoundaryTo(CropView.CropBoundary.BOTTOM,
+                                    savedInstanceState.getFloat(BOTTOM_BOUNDARY_KEY, 1f));
+                            mRestoringInstance = false;
+                            // Reuse the same path for subsequent restoration.
+                            mSavedImagePath = imagePath;
+                            Log.d(TAG, "Loaded bitmap from " + imagePath);
+                        });
+                    }
+                });
+            }
+        }
+        mPreview.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+                        updateCropLocation());
     }
 
     @Override
     public void onStart() {
         super.onStart();
-        if (mPreview.getDrawable() == null) {
+        if (mPreview.getDrawable() == null && !mRestoringInstance) {
             if (mConnection == null) {
                 Log.e(TAG, "Failed to get scroll capture connection, bailing out");
                 finishAndRemoveTask();
@@ -110,6 +175,24 @@
         }
     }
 
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(IMAGE_PATH_KEY, mSavedImagePath);
+        outState.putFloat(TOP_BOUNDARY_KEY, mCropView.getTopBoundary());
+        outState.putFloat(BOTTOM_BOUNDARY_KEY, mCropView.getBottomBoundary());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (isFinishing() && !TextUtils.isEmpty(mSavedImagePath)) {
+            Log.d(TAG, "Deleting " + mSavedImagePath);
+            File file = new File(mSavedImagePath);
+            file.delete();
+        }
+    }
+
     private void setButtonsEnabled(boolean enabled) {
         mSave.setEnabled(enabled);
         mCancel.setEnabled(enabled);
@@ -161,50 +244,111 @@
     }
 
     private void startExport(PendingAction action) {
-        mScrollCaptureController.startExport(mCropView.getTopBoundary(),
-                mCropView.getBottomBoundary(), new ScrollCaptureController.ExportCallback() {
-                    @Override
-                    public void onError() {
-                        Log.e(TAG, "Error exporting image data.");
-                        setButtonsEnabled(true);
-                    }
+        Drawable drawable = mPreview.getDrawable();
 
-                    @Override
-                    public void onExportComplete(Uri outputUri) {
-                        setButtonsEnabled(true);
-                        switch (action) {
-                            case EDIT:
-                                doEdit(outputUri);
-                                break;
-                            case SHARE:
-                                doShare(outputUri);
-                                break;
-                            case SAVE:
-                                // Nothing more to do
-                                finishAndRemoveTask();
-                                break;
-                        }
-                    }
-                });
+        Rect croppedPortion = new Rect(
+                0,
+                (int) (drawable.getIntrinsicHeight() * mCropView.getTopBoundary()),
+                drawable.getIntrinsicWidth(),
+                (int) (drawable.getIntrinsicHeight() * mCropView.getBottomBoundary()));
+        ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
+                mBackgroundExecutor, UUID.randomUUID(), getBitmap(croppedPortion, drawable),
+                ZonedDateTime.now());
+        exportFuture.addListener(() -> {
+            try {
+                ImageExporter.Result result = exportFuture.get();
+                setButtonsEnabled(true);
+                switch (action) {
+                    case EDIT:
+                        doEdit(result.uri);
+                        break;
+                    case SHARE:
+                        doShare(result.uri);
+                        break;
+                    case SAVE:
+                        // Nothing more to do
+                        finishAndRemoveTask();
+                        break;
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                Log.e(TAG, "failed to export", e);
+                setButtonsEnabled(true);
+            }
+        }, mUiExecutor);
+    }
+
+    private Bitmap getBitmap(Rect bounds, Drawable drawable) {
+        final RenderNode output = new RenderNode("Bitmap Export");
+        output.setPosition(0, 0, bounds.width(), bounds.height());
+        RecordingCanvas canvas = output.beginRecording();
+        // Translating the canvas instead of setting drawable bounds since the drawable is still
+        // used in the preview.
+        canvas.translate(0, -bounds.top);
+        drawable.draw(canvas);
+        output.endRecording();
+        return HardwareRenderer.createHardwareBitmap(output, bounds.width(), bounds.height());
+    }
+
+    private void saveCacheBitmap(ImageTileSet tileSet) {
+        long startTime = SystemClock.uptimeMillis();
+        Bitmap bitmap = tileSet.toBitmap();
+        // TODO(b/181562529) Remove this
+        mPreview.setImageDrawable(tileSet.getDrawable());
+        try {
+            File file = File.createTempFile("long_screenshot", ".png", null);
+            FileOutputStream stream = new FileOutputStream(file);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+            stream.flush();
+            stream.close();
+            mSavedImagePath = file.getAbsolutePath();
+            Log.d(TAG, "Saved to " + file.getAbsolutePath() + " in "
+                    + (SystemClock.uptimeMillis() - startTime) + "ms");
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to save bitmap", e);
+        }
+    }
+
+    private void updateCropLocation() {
+        Drawable drawable = mPreview.getDrawable();
+        if (drawable == null) {
+            return;
+        }
+
+        float imageRatio = drawable.getBounds().width() / (float) drawable.getBounds().height();
+        float viewRatio = mPreview.getWidth() / (float) mPreview.getHeight();
+
+        if (imageRatio > viewRatio) {
+            // Image is full width and height is constrained, compute extra padding to inform
+            // CropView
+            float imageHeight = mPreview.getHeight() * viewRatio / imageRatio;
+            int extraPadding = (int) (mPreview.getHeight() - imageHeight) / 2;
+            mCropView.setExtraPadding(extraPadding, extraPadding);
+        } else {
+            // Image is full height
+            mCropView.setExtraPadding(0, 0);
+        }
     }
 
     private void doCapture() {
         mScrollCaptureController.start(mConnection,
                 new ScrollCaptureController.ScrollCaptureCallback() {
-            @Override
-            public void onError() {
-                Log.e(TAG, "Error!");
-                finishAndRemoveTask();
-            }
+                    @Override
+                    public void onError() {
+                        Log.e(TAG, "Error capturing long screenshot!");
+                        finishAndRemoveTask();
+                    }
 
-            @Override
-            public void onComplete(ImageTileSet imageTileSet) {
-                Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
-                        + imageTileSet.getHeight());
-                mPreview.setImageDrawable(imageTileSet.getDrawable());
-                mMagnifierView.setImageTileset(imageTileSet);
-                mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
-            }
-        });
+                    @Override
+                    public void onComplete(ImageTileSet imageTileSet) {
+                        Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
+                                + imageTileSet.getHeight());
+                        mPreview.setImageDrawable(imageTileSet.getDrawable());
+                        updateCropLocation();
+                        mMagnifierView.setDrawable(imageTileSet.getDrawable(),
+                                imageTileSet.getWidth(), imageTileSet.getHeight());
+                        mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
+                        mBackgroundExecutor.execute(() -> saveCacheBitmap(imageTileSet));
+                    }
+                });
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
index f8f1d3a..90f3042 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.screenshot;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -27,6 +30,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 import androidx.annotation.Nullable;
 
@@ -34,7 +38,7 @@
 
 /**
  * MagnifierView shows a full-res cropped circular display of a given ImageTileSet, contents and
- * positioning dereived from events from a CropView to which it listens.
+ * positioning derived from events from a CropView to which it listens.
  *
  * Not meant to be a general-purpose magnifier!
  */
@@ -56,6 +60,20 @@
     private float mLastCropPosition;
     private CropView.CropBoundary mCropBoundary;
 
+    private ViewPropertyAnimator mTranslationAnimator;
+    private final Animator.AnimatorListener mTranslationAnimatorListener =
+            new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mTranslationAnimator = null;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mTranslationAnimator = null;
+        }
+    };
+
     public MagnifierView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -77,13 +95,12 @@
         mCheckerboardPaint.setColor(Color.GRAY);
     }
 
-    public void setImageTileset(ImageTileSet tiles) {
-        if (tiles != null) {
-            mDrawable = tiles.getDrawable();
-            mDrawable.setBounds(0, 0, tiles.getWidth(), tiles.getHeight());
-        } else {
-            mDrawable = null;
-        }
+    /**
+     * Set the drawable to be displayed by the magnifier.
+     */
+    public void setDrawable(@NonNull Drawable drawable, int width, int height) {
+        mDrawable = drawable;
+        mDrawable.setBounds(0, 0, width, height);
         invalidate();
     }
 
@@ -133,6 +150,8 @@
     public void onCropMotionEvent(MotionEvent event, CropView.CropBoundary boundary,
             float cropPosition, int cropPositionPx) {
         mCropBoundary = boundary;
+        boolean touchOnRight = event.getX() > getParentWidth() / 2;
+        float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mLastCropPosition = cropPosition;
@@ -144,11 +163,22 @@
                 setAlpha(0f);
                 setTranslationX((getParentWidth() - getWidth()) / 2);
                 setVisibility(View.VISIBLE);
-                boolean touchOnRight = event.getX() > getParentWidth() / 2;
-                float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
-                animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f).start();
+                mTranslationAnimator =
+                        animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f);
+                mTranslationAnimator.setListener(mTranslationAnimatorListener);
+                mTranslationAnimator.start();
                 break;
             case MotionEvent.ACTION_MOVE:
+                // The touch is near the middle if it's within 10% of the center point.
+                // We don't want to animate horizontally if the touch is near the middle.
+                boolean nearMiddle = Math.abs(event.getX() - getParentWidth() / 2)
+                        < getParentWidth() / 10f;
+                boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2;
+                if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) {
+                    mTranslationAnimator = animate().translationX(translateXTarget);
+                    mTranslationAnimator.setListener(mTranslationAnimatorListener);
+                    mTranslationAnimator.start();
+                }
                 mLastCropPosition = cropPosition;
                 setTranslationY(cropPositionPx - getHeight() / 2);
                 invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 805ac7c..3d6dea3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -519,7 +519,7 @@
         setWindowFocusable(true);
 
         if (mConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED, false)) {
+                SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED, true)) {
             View decorView = mWindow.getDecorView();
 
             // Wait until this window is attached to request because it is
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index 6cdf6ab..58a54f6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -82,7 +82,7 @@
                 dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
         if (intent != null) {
             final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
-                    mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED, null, UserHandle.CURRENT);
+                    mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
             b.setContentIntent(pendingIntent);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 4a3ffa45..9da6b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -18,7 +18,6 @@
 
 import android.annotation.UiThread;
 import android.content.Context;
-import android.graphics.Rect;
 import android.net.Uri;
 import android.provider.Settings;
 import android.util.Log;
@@ -27,11 +26,8 @@
 import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
 
-import com.google.common.util.concurrent.ListenableFuture;
-
 import java.time.ZonedDateTime;
 import java.util.UUID;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 /**
@@ -42,13 +38,15 @@
     private static final float MAX_PAGES_DEFAULT = 3f;
 
     private static final String SETTING_KEY_MAX_PAGES = "screenshot.scroll_max_pages";
+    // Portion of the tiles to be acquired above the starting position in infinite scroll
+    // situations. 1.0 means maximize the area above, 0 means just go down.
+    private static final float IDEAL_PORTION_ABOVE = 0.4f;
 
-    private static final int UP = -1;
-    private static final int DOWN = 1;
+    private boolean mScrollingUp = true;
+    // If true, stop acquiring images when no more bitmap data is available in the current direction
+    // or if the desired bitmap size is reached.
+    private boolean mFinishOnBoundary;
 
-    private int mDirection = DOWN;
-    private boolean mAtBottomEdge;
-    private boolean mAtTopEdge;
     private Session mSession;
 
     public static final int MAX_HEIGHT = 12000;
@@ -89,31 +87,9 @@
         connection.start(this::startCapture, maxPages);
     }
 
-    /**
-     * @param topCrop    [0,1) fraction of the top of the image to be cropped out.
-     * @param bottomCrop (0, 1] fraction to be cropped out, e.g. 0.7 will crop out the bottom 30%.
-     */
-    public void startExport(float topCrop, float bottomCrop, ExportCallback callback) {
-        Rect croppedPortion = new Rect(
-                0,
-                (int) (mImageTileSet.getHeight() * topCrop),
-                mImageTileSet.getWidth(),
-                (int) (mImageTileSet.getHeight() * bottomCrop));
-        ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
-                mBgExecutor, mRequestId, mImageTileSet.toBitmap(croppedPortion), mCaptureTime);
-        exportFuture.addListener(() -> {
-            try {
-                ImageExporter.Result result = exportFuture.get();
-                callback.onExportComplete(result.uri);
-            } catch (InterruptedException | ExecutionException e) {
-                Log.e(TAG, "failed to export", e);
-                callback.onError();
-            }
-        }, mUiExecutor);
-    }
-
     private void onCaptureResult(CaptureResult result) {
-        Log.d(TAG, "onCaptureResult: " + result);
+        Log.d(TAG, "onCaptureResult: " + result + " scrolling up: " + mScrollingUp
+                + " finish on boundary: " + mFinishOnBoundary);
         boolean emptyResult = result.captured.height() == 0;
         boolean partialResult = !emptyResult
                 && result.captured.height() < result.requested.height();
@@ -121,34 +97,28 @@
 
         if (partialResult || emptyResult) {
             // Potentially reached a vertical boundary. Extend in the other direction.
-            switch (mDirection) {
-                case DOWN:
-                    Log.d(TAG, "Reached bottom edge.");
-                    mAtBottomEdge = true;
-                    mDirection = UP;
-                    break;
-                case UP:
-                    Log.d(TAG, "Reached top edge.");
-                    mAtTopEdge = true;
-                    mDirection = DOWN;
-                    break;
-            }
-
-            if (mAtTopEdge && mAtBottomEdge) {
-                Log.d(TAG, "Reached both top and bottom edge, ending.");
+            if (mFinishOnBoundary) {
                 finish = true;
             } else {
-                // only reverse if the edge was relatively close to the starting point
-                if (mImageTileSet.getHeight() < mSession.getPageHeight() * 3) {
-                    Log.d(TAG, "Restarting in reverse direction.");
-
-                    // Because of temporary limitations, we cannot just jump to the opposite edge
-                    // and continue there. Instead, clear the results and start over capturing from
-                    // here in the other direction.
-                    mImageTileSet.clear();
-                } else {
-                    Log.d(TAG, "Capture is tall enough, stopping here.");
-                    finish = true;
+                // We hit a boundary, clear the tiles, capture everything in the opposite direction,
+                // then finish.
+                mImageTileSet.clear();
+                mFinishOnBoundary = true;
+                mScrollingUp = !mScrollingUp;
+            }
+        } else {
+            // Got the full requested result, but may have got enough bitmap data now
+            int expectedTiles = mImageTileSet.size() + 1;
+            boolean hitMaxTiles = expectedTiles >= mSession.getMaxTiles();
+            if (hitMaxTiles && mFinishOnBoundary) {
+                finish = true;
+            } else {
+                if (mScrollingUp) {
+                    if (expectedTiles >= mSession.getMaxTiles() * IDEAL_PORTION_ABOVE) {
+                        // We got enough above the start point, now see how far down it can go.
+                        mImageTileSet.clear();
+                        mScrollingUp = false;
+                    }
                 }
             }
         }
@@ -163,9 +133,8 @@
 
 
         // Stop when "too tall"
-        if (mImageTileSet.size() >= mSession.getMaxTiles()
-                || mImageTileSet.getHeight() > MAX_HEIGHT) {
-            Log.d(TAG, "Max height and/or tile count reached.");
+        if (mImageTileSet.getHeight() > MAX_HEIGHT) {
+            Log.d(TAG, "Max height reached.");
             finish = true;
         }
 
@@ -177,8 +146,8 @@
             return;
         }
 
-        int nextTop = (mDirection == DOWN) ? result.captured.bottom
-                : result.captured.top - mSession.getTileHeight();
+        int nextTop = (mScrollingUp)
+                ? result.captured.top - mSession.getTileHeight() : result.captured.bottom;
         Log.d(TAG, "requestTile: " + nextTop);
         mSession.requestTile(nextTop, /* consumer */ this::onCaptureResult);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
index 9ed9659..f2adaf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
@@ -207,7 +207,7 @@
             sb.append(g.toJson());
             count++;
         }
-        mLastSaveLen += count;
+        mLastSaveLen = count;
         sb.append("]");
         return sb.toString();
     }
@@ -249,9 +249,7 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         save();
         if (mLastSaveLen >= 0) {
-            pw.println(String.valueOf(mLastSaveLen)
-                    + " gestures since last dump written to " + mLogfile);
-            mLastSaveLen = 0;
+            pw.println(String.valueOf(mLastSaveLen) + " gestures written to " + mLogfile);
         } else {
             pw.println("error writing gestures");
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 01d3103..e5a960e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -83,6 +83,9 @@
     public static final int STATE_DOT = 1;
     public static final int STATE_HIDDEN = 2;
 
+    /** Maximum allowed width or height for an icon drawable */
+    private static final int MAX_IMAGE_SIZE = 500;
+
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -378,6 +381,13 @@
             Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
             return false;
         }
+
+        if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE
+                || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) {
+            Log.w(TAG, "Drawable is too large " + mIcon);
+            return false;
+        }
+
         if (withClear) {
             setImageDrawable(null);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 0ad6507..dff97a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.init
 
+import android.content.Context
+import android.provider.Settings
 import android.service.notification.StatusBarNotification
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
@@ -58,6 +60,7 @@
  */
 @SysUISingleton
 class NotificationsControllerImpl @Inject constructor(
+    private val context: Context,
     private val featureFlags: FeatureFlags,
     private val notificationListener: NotificationListener,
     private val entryManager: NotificationEntryManager,
@@ -129,7 +132,9 @@
             entryManager.attach(notificationListener)
         }
 
-        if (featureFlags.isPeopleTileEnabled) {
+        val showPeopleSpace = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.SHOW_PEOPLE_SPACE, 1)
+        if (showPeopleSpace == 1) {
             peopleSpaceWidgetManager.attach(notificationListener)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 1251b58..5206328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2052,8 +2052,7 @@
                 mNotificationLaunchHeight,
                 zProgress);
         setTranslationZ(translationZ);
-        float extraWidthForClipping = params.getWidth() - getWidth()
-                + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
+        float extraWidthForClipping = params.getWidth() - getWidth();
         setExtraWidthForClipping(extraWidthForClipping);
         int top = params.getTop();
         float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 7691761..b0b91bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -22,6 +22,8 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -30,6 +32,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.NotificationHeaderView;
@@ -1234,6 +1237,7 @@
         mCachedHeadsUpRemoteInput = null;
     }
 
+
     private RemoteInputView applyRemoteInput(View view, NotificationEntry entry,
             boolean hasRemoteInput, PendingIntent existingPendingIntent,
             RemoteInputView cachedView, NotificationViewWrapper wrapper) {
@@ -1271,6 +1275,15 @@
                 if (color == Notification.COLOR_DEFAULT) {
                     color = mContext.getColor(R.color.default_remote_input_background);
                 }
+                if (mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_tintNotificationsWithTheme)) {
+                    Resources.Theme theme = new ContextThemeWrapper(mContext,
+                            com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
+                    TypedArray ta = theme.obtainStyledAttributes(
+                            new int[]{com.android.internal.R.attr.colorAccent});
+                    color = ta.getColor(0, color);
+                    ta.recycle();
+                }
                 existing.setBackgroundColor(ContrastColorUtil.ensureTextBackgroundColor(color,
                         mContext.getColor(R.color.remote_input_text_enabled),
                         mContext.getColor(R.color.remote_input_hint)));
@@ -1342,12 +1355,10 @@
                 && isPersonWithShortcut
                 && entry.getBubbleMetadata() != null;
         if (showButton) {
-            Drawable d = mContext.getResources().getDrawable(entry.isBubble()
+            // explicitly resolve drawable resource using SystemUI's theme
+            Drawable d = mContext.getDrawable(entry.isBubble()
                     ? R.drawable.bubble_ic_stop_bubble
                     : R.drawable.bubble_ic_create_bubble);
-            mContainingNotification.updateNotificationColor();
-            final int tint = mContainingNotification.getNotificationColor();
-            d.setTint(tint);
 
             String contentDescription = mContext.getResources().getString(entry.isBubble()
                     ? R.string.notification_conversation_unbubble
@@ -1381,9 +1392,8 @@
             return;
         }
 
+        // explicitly resolve drawable resource using SystemUI's theme
         Drawable snoozeDrawable = mContext.getDrawable(R.drawable.ic_snooze);
-        mContainingNotification.updateNotificationColor();
-        snoozeDrawable.setTint(mContainingNotification.getNotificationColor());
         snoozeButton.setImageDrawable(snoozeDrawable);
 
         final NotificationSnooze snoozeGuts = (NotificationSnooze) LayoutInflater.from(mContext)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 756fe6c..8446b4e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -133,7 +133,7 @@
      */
     public static int getNotificationLaunchHeight(Context context) {
         int zDistance = getZDistanceBetweenElements(context);
-        return getBaseHeight(zDistance) * 2;
+        return NOTIFICATIONS_HAVE_SHADOWS ? 2 * getBaseHeight(zDistance) : 4 * zDistance;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 3833637..3739424 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -20,10 +20,12 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.drawable.ColorDrawable;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.util.Pair;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.NotificationHeaderView;
 import android.view.View;
@@ -33,6 +35,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.CachingIconView;
+import com.android.internal.widget.NotificationExpandButton;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.NotificationGroupingUtil;
@@ -103,6 +106,8 @@
     private ViewGroup mCurrentHeader;
     private boolean mIsConversation;
 
+    private boolean mTintWithThemeAccent;
+    private boolean mShowGroupCountInExpander;
     private boolean mShowDividersWhenExpanded;
     private boolean mHideDividersDuringExpand;
     private int mTranslationForHeader;
@@ -145,6 +150,10 @@
                 com.android.internal.R.dimen.notification_content_margin);
         mEnableShadowOnChildNotifications =
                 res.getBoolean(R.bool.config_enableShadowOnChildNotifications);
+        mTintWithThemeAccent =
+                res.getBoolean(com.android.internal.R.bool.config_tintNotificationsWithTheme);
+        mShowGroupCountInExpander =
+                res.getBoolean(R.bool.config_showNotificationGroupCountInExpander);
         mShowDividersWhenExpanded =
                 res.getBoolean(R.bool.config_showDividersWhenGroupNotificationExpanded);
         mHideDividersDuringExpand =
@@ -229,7 +238,6 @@
             mNotificationHeader.measure(widthMeasureSpec, headerHeightSpec);
         }
         if (mNotificationHeaderLowPriority != null) {
-            headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
             mNotificationHeaderLowPriority.measure(widthMeasureSpec, headerHeightSpec);
         }
 
@@ -397,7 +405,20 @@
         mGroupingUtil.updateChildrenAppearance();
     }
 
+    private void setExpandButtonNumber(NotificationViewWrapper wrapper) {
+        View expandButton = wrapper == null
+                ? null : wrapper.getExpandButton();
+        if (expandButton instanceof NotificationExpandButton) {
+            ((NotificationExpandButton) expandButton).setNumber(mUntruncatedChildCount);
+        }
+    }
+
     public void updateGroupOverflow() {
+        if (mShowGroupCountInExpander) {
+            setExpandButtonNumber(mNotificationHeaderWrapper);
+            setExpandButtonNumber(mNotificationHeaderWrapperLowPriority);
+            return;
+        }
         int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
         if (mUntruncatedChildCount > maxAllowedVisibleChildren) {
             int number = mUntruncatedChildCount - maxAllowedVisibleChildren;
@@ -1201,8 +1222,21 @@
     }
 
     public void onNotificationUpdated() {
-        mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
-                mContainingNotification.getNotificationColor());
+        if (mShowGroupCountInExpander) {
+            // The overflow number is not used, so its color is irrelevant; skip this
+            return;
+        }
+        int color = mContainingNotification.getNotificationColor();
+        if (mTintWithThemeAccent) {
+            // We're using the theme accent, color with the accent color instead of the notif color
+            Resources.Theme theme = new ContextThemeWrapper(mContext,
+                    com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
+            TypedArray ta = theme.obtainStyledAttributes(
+                    new int[]{com.android.internal.R.attr.colorAccent});
+            color = ta.getColor(0, color);
+            ta.recycle();
+        }
+        mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, color);
     }
 
     public int getPositionInLinearLayout(View childInGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index e40c262..204dd9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.hardware.display.ColorDisplayManager;
@@ -27,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.policy.CastController;
@@ -41,6 +44,8 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
+import javax.inject.Named;
+
 /**
  * Manages which tiles should be automatically added to QS.
  */
@@ -69,6 +74,8 @@
     private final ManagedProfileController mManagedProfileController;
     private final NightDisplayListener mNightDisplayListener;
     private final CastController mCastController;
+    private final ReduceBrightColorsController mReduceBrightColorsController;
+    private final boolean mIsReduceBrightColorsAvailable;
     private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
 
     public AutoTileManager(Context context, AutoAddTracker.Builder autoAddTrackerBuilder,
@@ -79,7 +86,9 @@
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
             NightDisplayListener nightDisplayListener,
-            CastController castController) {
+            CastController castController,
+            ReduceBrightColorsController reduceBrightColorsController,
+            @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
         mContext = context;
         mHost = host;
         mSecureSettings = secureSettings;
@@ -91,6 +100,8 @@
         mManagedProfileController = managedProfileController;
         mNightDisplayListener = nightDisplayListener;
         mCastController = castController;
+        mReduceBrightColorsController = reduceBrightColorsController;
+        mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable;
     }
 
     /**
@@ -124,9 +135,9 @@
         if (!mAutoTracker.isAdded(CAST)) {
             mCastController.addCallback(mCastCallback);
         }
-
-        // TODO(b/170970675): Set a listener/controller and callback for Reduce Bright Colors
-        // state changes. Call into ColorDisplayService to get availability/config status
+        if (!mAutoTracker.isAdded(BRIGHTNESS) && mIsReduceBrightColorsAvailable) {
+            mReduceBrightColorsController.addCallback(mReduceBrightColorsCallback);
+        }
 
         int settingsN = mAutoAddSettingList.size();
         for (int i = 0; i < settingsN; i++) {
@@ -143,6 +154,9 @@
         if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             mNightDisplayListener.setCallback(null);
         }
+        if (mIsReduceBrightColorsAvailable) {
+            mReduceBrightColorsController.removeCallback(mReduceBrightColorsCallback);
+        }
         mCastController.removeCallback(mCastCallback);
         int settingsN = mAutoAddSettingList.size();
         for (int i = 0; i < settingsN; i++) {
@@ -287,6 +301,24 @@
     };
 
     @VisibleForTesting
+    final ReduceBrightColorsController.Listener mReduceBrightColorsCallback =
+            new ReduceBrightColorsController.Listener() {
+                @Override
+                public void onActivated(boolean activated) {
+                    if (activated) {
+                        addReduceBrightColorsTile();
+                    }
+                }
+
+                private void addReduceBrightColorsTile() {
+                    if (mAutoTracker.isAdded(BRIGHTNESS)) return;
+                    mHost.addTile(BRIGHTNESS);
+                    mAutoTracker.setTileAdded(BRIGHTNESS);
+                    mHandler.post(() -> mReduceBrightColorsController.removeCallback(this));
+                }
+            };
+
+    @VisibleForTesting
     final CastController.Callback mCastCallback = new CastController.Callback() {
         @Override
         public void onCastDevicesChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 986333c..80109cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,7 +19,6 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
-import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
@@ -74,10 +73,6 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.controls.dagger.ControlsComponent;
-import com.android.systemui.controls.ui.ControlsDialog;
-import com.android.systemui.controls.ui.ControlsUiController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.IntentButtonProvider;
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
@@ -130,7 +125,7 @@
 
     private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
-    private ImageView mAltLeftButton;
+    private ImageView mWalletButton;
     private ViewGroup mIndicationArea;
     private TextView mIndicationText;
     private TextView mIndicationTextBottom;
@@ -179,11 +174,7 @@
     private int mBurnInXOffset;
     private int mBurnInYOffset;
     private ActivityIntentHelper mActivityIntentHelper;
-
-    private ControlsDialog mControlsDialog;
-    private ControlsComponent mControlsComponent;
     private int mLockScreenMode;
-    private BroadcastDispatcher mBroadcastDispatcher;
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     public KeyguardBottomAreaView(Context context) {
@@ -251,7 +242,7 @@
         mOverlayContainer = findViewById(R.id.overlay_container);
         mRightAffordanceView = findViewById(R.id.camera_button);
         mLeftAffordanceView = findViewById(R.id.left_button);
-        mAltLeftButton = findViewById(R.id.alt_left_button);
+        mWalletButton = findViewById(R.id.wallet_button);
         mIndicationArea = findViewById(R.id.keyguard_indication_area);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
@@ -351,10 +342,10 @@
         mLeftAffordanceView.setLayoutParams(lp);
         updateLeftAffordanceIcon();
 
-        lp = mAltLeftButton.getLayoutParams();
+        lp = mWalletButton.getLayoutParams();
         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
         lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
-        mAltLeftButton.setLayoutParams(lp);
+        mWalletButton.setLayoutParams(lp);
     }
 
     private void updateRightAffordanceIcon() {
@@ -427,11 +418,11 @@
         mLeftAffordanceView.setContentDescription(state.contentDescription);
     }
 
-    private void updateControlsVisibility() {
-        if (mDozing || mControlsComponent.getVisibility() != AVAILABLE) {
-            mAltLeftButton.setVisibility(GONE);
+    private void updateWalletVisibility() {
+        if (mDozing) {
+            mWalletButton.setVisibility(GONE);
         } else {
-            mAltLeftButton.setVisibility(VISIBLE);
+            mWalletButton.setVisibility(VISIBLE);
         }
     }
 
@@ -699,8 +690,8 @@
 
     public void startFinishDozeAnimation() {
         long delay = 0;
-        if (mAltLeftButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mAltLeftButton, delay);
+        if (mWalletButton.getVisibility() == View.VISIBLE) {
+            startFinishDozeAnimationElement(mWalletButton, delay);
         }
         if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
             startFinishDozeAnimationElement(mLeftAffordanceView, delay);
@@ -774,14 +765,10 @@
 
         updateCameraVisibility();
         updateLeftAffordanceIcon();
-        updateControlsVisibility();
+        updateWalletVisibility();
 
         if (dozing) {
             mOverlayContainer.setVisibility(INVISIBLE);
-            if (mControlsDialog != null) {
-                mControlsDialog.dismiss();
-                mControlsDialog = null;
-            }
         } else {
             mOverlayContainer.setVisibility(VISIBLE);
             if (animate) {
@@ -811,7 +798,7 @@
         mLeftAffordanceView.setAlpha(alpha);
         mRightAffordanceView.setAlpha(alpha);
         mIndicationArea.setAlpha(alpha);
-        mAltLeftButton.setAlpha(alpha);
+        mWalletButton.setAlpha(alpha);
     }
 
     private class DefaultLeftButton implements IntentButton {
@@ -884,38 +871,18 @@
         return insets;
     }
 
-    /**
-     * Show or hide controls, depending on the lock screen mode and controls
-     * availability.
-     */
-    public void setupControls(ControlsComponent component, BroadcastDispatcher dispatcher) {
-        mControlsComponent = component;
-        mBroadcastDispatcher = dispatcher;
-        setupControls();
-    }
-
-    private void setupControls() {
+    private void setupWallet() {
         boolean inNewLayout = mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
         boolean settingEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 "controls_lockscreen", 0) == 1;
-        if (!inNewLayout || !settingEnabled || !mControlsComponent.isEnabled()) {
-            mAltLeftButton.setVisibility(View.GONE);
+        if (!inNewLayout || !settingEnabled) {
+            mWalletButton.setVisibility(View.GONE);
             return;
         }
 
-        mControlsComponent.getControlsListingController().get()
-                .addCallback(list -> {
-                    if (!list.isEmpty()) {
-                        mAltLeftButton.setImageDrawable(list.get(0).loadIcon());
-                        mAltLeftButton.setOnClickListener((v) -> {
-                            ControlsUiController ui = mControlsComponent
-                                    .getControlsUiController().get();
-                            mControlsDialog = new ControlsDialog(mContext, mBroadcastDispatcher)
-                                    .show(ui);
-                        });
-                    }
-                    updateControlsVisibility();
-                });
+        // TODO: add image
+        //        mWalletButton.setImageDrawable(list.get(0).loadIcon());
+        updateWalletVisibility();
     }
 
     /**
@@ -923,6 +890,6 @@
      */
     public void onLockScreenModeChanged(int mode) {
         mLockScreenMode = mode;
-        setupControls();
+        setupWallet();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 83c347b..ae14fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -89,10 +89,8 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeLog;
@@ -245,7 +243,6 @@
                 public void onLockScreenModeChanged(int mode) {
                     mLockScreenMode = mode;
                     mClockPositionAlgorithm.onLockScreenModeChanged(mode);
-                    mKeyguardBottomArea.onLockScreenModeChanged(mode);
                 }
 
                 @Override
@@ -304,7 +301,6 @@
     private final QSDetailDisplayer mQSDetailDisplayer;
     private final FeatureFlags mFeatureFlags;
     private final ScrimController mScrimController;
-    private final ControlsComponent mControlsComponent;
 
     // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
     // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
@@ -520,7 +516,6 @@
     private NotificationShelfController mNotificationShelfController;
 
     private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
-    private BroadcastDispatcher mBroadcastDispatcher;
 
     private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
         @Override
@@ -578,9 +573,7 @@
             UserManager userManager,
             MediaDataManager mediaDataManager,
             AmbientState ambientState,
-            FeatureFlags featureFlags,
-            ControlsComponent controlsComponent,
-            BroadcastDispatcher broadcastDispatcher) {
+            FeatureFlags featureFlags) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
                 latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager,
@@ -623,7 +616,6 @@
         mScrimController = scrimController;
         mUserManager = userManager;
         mMediaDataManager = mediaDataManager;
-        mControlsComponent = controlsComponent;
         pulseExpansionHandler.setPulseExpandAbortListener(() -> {
             if (mQs != null) {
                 mQs.animateHeaderSlidingOut();
@@ -662,7 +654,6 @@
         mEntryManager = notificationEntryManager;
         mConversationNotificationManager = conversationNotificationManager;
         mAuthController = authController;
-        mBroadcastDispatcher = broadcastDispatcher;
 
         mView.setBackgroundColor(Color.TRANSPARENT);
         OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
@@ -972,7 +963,6 @@
         mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
         mKeyguardBottomArea.setStatusBar(mStatusBar);
         mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
-        mKeyguardBottomArea.setupControls(mControlsComponent, mBroadcastDispatcher);
     }
 
     private void updateMaxDisplayedNotifications(boolean recompute) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 55744f9..b6ed3e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -27,7 +27,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.annotation.Nullable;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.SystemClock;
@@ -1243,7 +1242,10 @@
                     mVelocityTracker.clear();
                     break;
             }
-            return false;
+
+            // Finally, if none of the above cases applies, ensure that touches do not get handled
+            // by the contents of a panel that is not showing (a bit of a hack to avoid b/178277858)
+            return (mView.getVisibility() != View.VISIBLE);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b25fced..bf36435 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -78,7 +78,6 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -277,8 +276,7 @@
     public static final boolean DEBUG = false;
     public static final boolean SPEW = false;
     public static final boolean DUMPTRUCK = true; // extra dumpsys info
-    public static final boolean DEBUG_GESTURES = Build.IS_DEBUGGABLE; // TODO(b/178277858)
-    public static final boolean DEBUG_GESTURES_VERBOSE = true;
+    public static final boolean DEBUG_GESTURES = false;
     public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
     public static final boolean DEBUG_CAMERA_LIFT = false;
 
@@ -458,7 +456,9 @@
     private final DisplayMetrics mDisplayMetrics;
 
     // XXX: gesture research
-    private GestureRecorder mGestureRec = null;
+    private final GestureRecorder mGestureRec = DEBUG_GESTURES
+        ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
+        : null;
 
     private final ScreenPinningRequest mScreenPinningRequest;
 
@@ -856,10 +856,6 @@
 
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         DateTimeView.setReceiverHandler(timeTickHandler);
-
-        if (DEBUG_GESTURES) {
-            mGestureRec = new GestureRecorder(mContext.getCacheDir() + "/statusbar_gestures.dat");
-        }
     }
 
     @Override
@@ -2271,7 +2267,7 @@
 
     public boolean interceptTouchEvent(MotionEvent event) {
         if (DEBUG_GESTURES) {
-            if (DEBUG_GESTURES_VERBOSE || event.getActionMasked() != MotionEvent.ACTION_MOVE) {
+            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
                 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
                         event.getActionMasked(), (int) event.getX(), (int) event.getY(),
                         mDisabled1, mDisabled2);
@@ -2696,6 +2692,10 @@
         return mDisplay.getRotation();
     }
 
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
             boolean dismissShade, int flags) {
         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
@@ -2721,7 +2721,7 @@
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.addFlags(flags);
             int result = ActivityManager.START_CANCELED;
-            ActivityOptions options = new ActivityOptions(getActivityOptions(
+            ActivityOptions options = new ActivityOptions(getActivityOptions(mDisplayId,
                     null /* remoteAnimation */));
             options.setDisallowEnterPictureInPictureWhileLaunching(
                     disallowEnterPictureInPictureWhileLaunching);
@@ -4366,6 +4366,7 @@
         executeActionDismissingKeyguard(() -> {
             try {
                 intent.send(null, 0, null, null, null, null, getActivityOptions(
+                        mDisplayId,
                         mActivityLaunchAnimator.getLaunchAnimation(associatedView, isOccluded())));
             } catch (PendingIntent.CanceledException e) {
                 // the stack trace isn't very helpful here.
@@ -4387,15 +4388,38 @@
         mMainThreadHandler.post(runnable);
     }
 
-    public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
+    /**
+     * Returns an ActivityOptions bundle created using the given parameters.
+     *
+     * @param displayId The ID of the display to launch the activity in. Typically this would be the
+     *                  display the status bar is on.
+     * @param animationAdapter The animation adapter used to start this activity, or {@code null}
+     *                         for the default animation.
+     */
+    public static Bundle getActivityOptions(int displayId,
+            @Nullable RemoteAnimationAdapter animationAdapter) {
         return getDefaultActivityOptions(animationAdapter).toBundle();
     }
 
-    public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter,
-            boolean isKeyguardShowing, long eventTime) {
+    /**
+     * Returns an ActivityOptions bundle created using the given parameters.
+     *
+     * @param displayId The ID of the display to launch the activity in. Typically this would be the
+     *                  display the status bar is on.
+     * @param animationAdapter The animation adapter used to start this activity, or {@code null}
+     *                         for the default animation.
+     * @param isKeyguardShowing Whether keyguard is currently showing.
+     * @param eventTime The event time in milliseconds since boot, not including sleep. See
+     *                  {@link ActivityOptions#setSourceInfo}.
+     */
+    public static Bundle getActivityOptions(int displayId,
+            @Nullable RemoteAnimationAdapter animationAdapter, boolean isKeyguardShowing,
+            long eventTime) {
         ActivityOptions options = getDefaultActivityOptions(animationAdapter);
         options.setSourceInfo(isKeyguardShowing ? ActivityOptions.SourceInfo.TYPE_LOCKSCREEN
                 : ActivityOptions.SourceInfo.TYPE_NOTIFICATION, eventTime);
+        options.setLaunchDisplayId(displayId);
+        options.setCallerDisplayId(displayId);
         return options.toBundle();
     }
 
@@ -4535,4 +4559,8 @@
     public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
         mExpansionChangedListeners.add(listener);
     }
+
+    public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
+        mExpansionChangedListeners.remove(listener);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 598addc..34673f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -427,8 +427,13 @@
                                 intent.getCreatorPackage(), adapter);
             }
             long eventTime = row.getAndResetLastActionUpTime();
-            Bundle options = eventTime > 0 ? getActivityOptions(adapter,
-                    mKeyguardStateController.isShowing(), eventTime) : getActivityOptions(adapter);
+            Bundle options = eventTime > 0
+                    ? getActivityOptions(
+                            mStatusBar.getDisplayId(),
+                            adapter,
+                            mKeyguardStateController.isShowing(),
+                            eventTime)
+                    : getActivityOptions(mStatusBar.getDisplayId(), adapter);
             int launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
                     null, null, options);
             mMainThreadHandler.post(() -> {
@@ -450,6 +455,7 @@
                 int launchResult = TaskStackBuilder.create(mContext)
                         .addNextIntentWithParentStack(intent)
                         .startActivities(getActivityOptions(
+                                mStatusBar.getDisplayId(),
                                 mActivityLaunchAnimator.getLaunchAnimation(
                                         row, mStatusBar.isOccluded())),
                                 new UserHandle(UserHandle.getUserId(appUid)));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 38f3bc8..59c1138 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -94,15 +94,6 @@
                             goingToFullShade,
                             oldState);
                 }
-
-                @Override
-                public void onDozeAmountChanged(float linearAmount, float amount) {
-                    if (DEBUG) {
-                        Log.d(TAG, String.format("onDozeAmountChanged: linearAmount=%f amount=%f",
-                                linearAmount, amount));
-                    }
-                    setDarkAmount(amount);
-                }
             };
 
     @Inject
@@ -294,20 +285,6 @@
         }
     }
 
-    /**
-     * Set the amount (ratio) that the device has transitioned to doze.
-     *
-     * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
-     */
-    private void setDarkAmount(float darkAmount) {
-        boolean isAwake = darkAmount != 0;
-        if (darkAmount == mDarkAmount) {
-            return;
-        }
-        mDarkAmount = darkAmount;
-        mView.setVisibility(isAwake ? View.VISIBLE : View.GONE);
-    }
-
     private boolean isListAnimating() {
         return mKeyguardVisibilityHelper.isVisibilityAnimating();
     }
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 8845a05..5a80c05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -205,7 +205,7 @@
     protected void onViewAttached() {
         if (DEBUG) Log.d(TAG, "onViewAttached");
         mAdapter.registerDataSetObserver(mDataSetObserver);
-        mDataSetObserver.onChanged();
+        mAdapter.notifyDataSetChanged();
         mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
         mStatusBarStateController.addCallback(mStatusBarStateListener);
         mScreenLifecycle.addObserver(mScreenObserver);
@@ -373,14 +373,13 @@
      * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
      */
     private void setDarkAmount(float darkAmount) {
-        boolean isAwake = darkAmount != 0;
+        boolean isFullyDozed = darkAmount == 1;
         if (darkAmount == mDarkAmount) {
             return;
         }
         mDarkAmount = darkAmount;
         mListView.setDarkAmount(darkAmount);
-        mView.setVisibility(isAwake ? View.VISIBLE : View.GONE);
-        if (!isAwake) {
+        if (isFullyDozed) {
             closeSwitcherIfOpenAndNotSimple(false);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 6c097bd..044f52f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -383,8 +383,15 @@
             int qsTypeIcon = 0;
             IconState qsIcon = null;
             CharSequence description = null;
+            // Mobile icon will only be shown in the statusbar in 2 scenarios
+            // 1. Mobile is the default network, and it is validated
+            // 2. Mobile is the default network, it is not validated and there is no other
+            // non-Carrier WiFi networks available.
+            boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
+                    || (mCurrentState.inetCondition == 0
+                            && !mNetworkController.isNonCarrierWifiNetworkAvailable());
             // Only send data sim callbacks to QS.
-            if (mCurrentState.dataSim && mCurrentState.isDefault) {
+            if (mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons) {
                 qsTypeIcon =
                         (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.qsDataType : 0;
                 qsIcon = new IconState(mCurrentState.enabled
@@ -397,7 +404,7 @@
             boolean activityOut = mCurrentState.dataConnected
                     && !mCurrentState.carrierNetworkChangeMode
                     && mCurrentState.activityOut;
-            showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault;
+            showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons;
             boolean showTriangle = showDataIcon && !mCurrentState.airplaneMode;
             int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0;
             showDataIcon |= mCurrentState.roaming;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 8eb1e64..fbdaf9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -547,6 +547,10 @@
         return mWifiSignalController.isCarrierMergedWifi(subId);
     }
 
+    boolean isNonCarrierWifiNetworkAvailable() {
+        return !mNoNetworksAvailable;
+    }
+
     boolean isEthernetDefault() {
         return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
     }
@@ -908,6 +912,11 @@
         return true;
     }
 
+    @VisibleForTesting
+    void setNoNetworksAvailable(boolean noNetworksAvailable) {
+        mNoNetworksAvailable = noNetworksAvailable;
+    }
+
     private void updateAirplaneMode(boolean force) {
         boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 738cab1..5638503 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -439,7 +439,7 @@
     private final NetworkCallback mNetworkCallback = new NetworkCallback() {
         @Override
         public void onAvailable(Network network) {
-            if (DEBUG) Log.d(TAG, "onAvailable " + network.netId);
+            if (DEBUG) Log.d(TAG, "onAvailable " + network.getNetId());
             updateState();
             fireCallbacks();
         };
@@ -448,7 +448,7 @@
         // how long the VPN connection is held on to.
         @Override
         public void onLost(Network network) {
-            if (DEBUG) Log.d(TAG, "onLost " + network.netId);
+            if (DEBUG) Log.d(TAG, "onLost " + network.getNetId());
             updateState();
             fireCallbacks();
         };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 8d72c9c8..b9b62b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -106,10 +106,18 @@
         if (mCurrentState.inetCondition == 0) {
             contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
         }
-        IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
         if (mProviderModel) {
+            // WiFi icon will only be shown in the statusbar in 2 scenarios
+            // 1. WiFi is the default network, and it is validated
+            // 2. WiFi is the default network, it is not validated and there is no other
+            // non-Carrier WiFi networks available.
+            boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
+                    || (mCurrentState.inetCondition == 0
+                            && !mNetworkController.isNonCarrierWifiNetworkAvailable());
+            IconState statusIcon = new IconState(
+                    wifiVisible && maybeShowIcons, getCurrentIconId(), contentDescription);
             IconState qsIcon = null;
-            if (mCurrentState.isDefault || (!mNetworkController.isRadioOn()
+            if ((mCurrentState.isDefault && maybeShowIcons) || (!mNetworkController.isRadioOn()
                     && !mNetworkController.isEthernetDefault())) {
                 qsIcon = new IconState(mCurrentState.connected,
                         mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
@@ -123,6 +131,8 @@
             );
             callback.setWifiIndicators(wifiIndicators);
         } else {
+            IconState statusIcon = new IconState(
+                    wifiVisible, getCurrentIconId(), contentDescription);
             IconState qsIcon = new IconState(mCurrentState.connected,
                     mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
                             : getQsCurrentIconId(), contentDescription);
@@ -146,15 +156,25 @@
         if (mCurrentState.inetCondition == 0) {
             dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
         }
-        boolean qsVisible = mCurrentState.enabled
-                && (mCurrentState.connected && mCurrentState.inetCondition == 1);
-
+        // Mobile icon will only be shown in the statusbar in 2 scenarios
+        // 1. Mobile is the default network, and it is validated
+        // 2. Mobile is the default network, it is not validated and there is no other
+        // non-Carrier WiFi networks available.
+        boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
+                || (mCurrentState.inetCondition == 0
+                        && !mNetworkController.isNonCarrierWifiNetworkAvailable());
+        boolean sbVisible = mCurrentState.enabled && mCurrentState.connected
+                && maybeShowIcons && mCurrentState.isDefault;
         IconState statusIcon =
-                new IconState(qsVisible, getCurrentIconIdForCarrierWifi(), contentDescription);
-        int qsTypeIcon = mCurrentState.connected ? icons.qsDataType : 0;
-        int typeIcon = mCurrentState.connected ? icons.dataType : 0;
-        IconState qsIcon = new IconState(
-                mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), contentDescription);
+                new IconState(sbVisible, getCurrentIconIdForCarrierWifi(), contentDescription);
+        int typeIcon = sbVisible ? icons.dataType : 0;
+        int qsTypeIcon = 0;
+        IconState qsIcon = null;
+        if (sbVisible) {
+            qsTypeIcon = icons.qsDataType;
+            qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(),
+                    contentDescription);
+        }
         CharSequence description =
                 mNetworkController.getNetworkNameForCarrierWiFi(mCurrentState.subId);
         MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 5d02845..f192287 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -43,7 +43,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -87,12 +86,6 @@
     protected static final int SECONDARY = 1;
     protected static final int NEUTRAL = 2;
 
-    // If lock screen wallpaper colors should also be considered when selecting the theme.
-    // Doing this has performance impact, given that overlays would need to be swapped when
-    // the device unlocks.
-    @VisibleForTesting
-    static final boolean USE_LOCK_SCREEN_WALLPAPER = false;
-
     private final ThemeOverlayApplier mThemeManager;
     private final UserManager mUserManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
@@ -103,7 +96,6 @@
     private final WallpaperManager mWallpaperManager;
     private final KeyguardStateController mKeyguardStateController;
     private final boolean mIsMonetEnabled;
-    private WallpaperColors mLockColors;
     private WallpaperColors mSystemColors;
     // If fabricated overlays were already created for the current theme.
     private boolean mNeedsOverlayCreation;
@@ -117,6 +109,8 @@
     private FabricatedOverlay mSecondaryOverlay;
     // Neutral system colors overlay
     private FabricatedOverlay mNeutralOverlay;
+    // If wallpaper color event will be accepted and change the UI colors.
+    private boolean mAcceptColorEvents = true;
 
     @Inject
     public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
@@ -146,13 +140,20 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
         mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
-                reevaluateSystemTheme(true /* forceReload */);
+                if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())
+                        || Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction())) {
+                    if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
+                    reevaluateSystemTheme(true /* forceReload */);
+                } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
+                    mAcceptColorEvents = true;
+                    Log.i(TAG, "Allowing color events again");
+                }
             }
-        }, filter, mBgExecutor, UserHandle.ALL);
+        }, filter, mMainExecutor, UserHandle.ALL);
         mSecureSettings.registerContentObserverForUser(
                 Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
                 false,
@@ -170,38 +171,22 @@
 
         // Upon boot, make sure we have the most up to date colors
         mBgExecutor.execute(() -> {
-            WallpaperColors lockColors = mWallpaperManager.getWallpaperColors(
-                    WallpaperManager.FLAG_LOCK);
             WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
                     WallpaperManager.FLAG_SYSTEM);
             mMainExecutor.execute(() -> {
-                if (USE_LOCK_SCREEN_WALLPAPER) {
-                    mLockColors = lockColors;
-                }
                 mSystemColors = systemColor;
                 reevaluateSystemTheme(false /* forceReload */);
             });
         });
-        if (USE_LOCK_SCREEN_WALLPAPER) {
-            mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
-                @Override
-                public void onKeyguardShowingChanged() {
-                    if (mLockColors == null) {
-                        return;
-                    }
-                    // It's possible that the user has a lock screen wallpaper. On this case we'll
-                    // end up with different colors after unlocking.
-                    reevaluateSystemTheme(false /* forceReload */);
-                }
-            });
-        }
         mWallpaperManager.addOnColorsChangedListener((wallpaperColors, which) -> {
-            if (USE_LOCK_SCREEN_WALLPAPER && (which & WallpaperManager.FLAG_LOCK) != 0) {
-                mLockColors = wallpaperColors;
-                if (DEBUG) {
-                    Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
-                }
+            if (!mAcceptColorEvents) {
+                Log.i(TAG, "Wallpaper color event rejected: " + wallpaperColors);
+                return;
             }
+            if (wallpaperColors != null && mAcceptColorEvents) {
+                mAcceptColorEvents = false;
+            }
+
             if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
                 mSystemColors = wallpaperColors;
                 if (DEBUG) {
@@ -213,10 +198,7 @@
     }
 
     private void reevaluateSystemTheme(boolean forceReload) {
-        WallpaperColors currentColors =
-                mKeyguardStateController.isShowing() && mLockColors != null
-                        ? mLockColors : mSystemColors;
-
+        final WallpaperColors currentColors = mSystemColors;
         final int mainColor;
         final int accentCandidate;
         if (currentColors == null) {
@@ -378,8 +360,6 @@
 
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
-        pw.println("USE_LOCK_SCREEN_WALLPAPER=" + USE_LOCK_SCREEN_WALLPAPER);
-        pw.println("mLockColors=" + mLockColors);
         pw.println("mSystemColors=" + mSystemColors);
         pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
         pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor));
@@ -388,5 +368,6 @@
         pw.println("mNeutralOverlay=" + mNeutralOverlay);
         pw.println("mIsMonetEnabled=" + mIsMonetEnabled);
         pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation);
+        pw.println("mAcceptColorEvents=" + mAcceptColorEvents);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 25345d5..5dc7006 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -778,6 +778,12 @@
 
     /** Animates away the ringer drawer. */
     private void hideRingerDrawer() {
+
+        // If the ringer drawer isn't present, don't try to hide it.
+        if (mRingerDrawerContainer == null) {
+            return;
+        }
+
         // Hide the drawer icon for the selected ringer - it's visible in the ringer button and we
         // don't want to be able to see it while it animates away.
         getDrawerIconViewForMode(mState.ringerModeInternal).setVisibility(INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 4611fe03..78cd3a82 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -77,6 +77,8 @@
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.StartingSurface;
+import com.android.wm.shell.startingsurface.StartingWindowController;
 import com.android.wm.shell.transition.RemoteTransitions;
 import com.android.wm.shell.transition.Transitions;
 
@@ -373,6 +375,9 @@
         return new PipUiEventLogger(uiEventLogger, packageManager);
     }
 
+    @BindsOptionalOf
+    abstract PipTouchHandler optionalPipTouchHandler();
+
     //
     // Shell transitions
     //
@@ -448,6 +453,22 @@
     @BindsOptionalOf
     abstract AppPairsController optionalAppPairs();
 
+    // Starting window
+
+    @WMSingleton
+    @Provides
+    static Optional<StartingSurface> provideStartingSurface(
+            StartingWindowController startingWindowController) {
+        return Optional.of(startingWindowController.asStartingSurface());
+    }
+
+    @WMSingleton
+    @Provides
+    static StartingWindowController provideStartingWindowController(Context context,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        return new StartingWindowController(context, mainExecutor);
+    }
+
     //
     // Task view factory
     //
@@ -479,6 +500,8 @@
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
+            Optional<StartingSurface> startingSurface,
+            Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
             @ShellMainThread ShellExecutor mainExecutor) {
@@ -488,6 +511,8 @@
                 legacySplitScreenOptional,
                 splitScreenOptional,
                 appPairsOptional,
+                startingSurface,
+                pipTouchHandlerOptional,
                 fullscreenTaskListener,
                 transitions,
                 mainExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 854be1f..1783fa4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -17,6 +17,7 @@
 package com.android.keyguard;
 
 import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.systemBars;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -24,13 +25,20 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.graphics.Insets;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.WindowInsetsController;
+import android.widget.FrameLayout;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -45,12 +53,21 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityContainerTest extends SysuiTestCase {
+    private static final int SCREEN_WIDTH = 1600;
+    private static final int FAKE_MEASURE_SPEC =
+            View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY);
+
+    private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN;
+    private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password;
+
+
 
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
 
     @Mock
     private WindowInsetsController mWindowInsetsController;
+
     @Mock
     private KeyguardSecurityViewFlipper mSecurityViewFlipper;
 
@@ -58,9 +75,18 @@
 
     @Before
     public void setup() {
+        // Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache
+        // the real references (rather than the TestableResources that this call creates).
+        mContext.ensureTestableResources();
+        FrameLayout.LayoutParams securityViewFlipperLayoutParams = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+
         when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+        when(mSecurityViewFlipper.getLayoutParams()).thenReturn(securityViewFlipperLayoutParams);
         mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
         mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+        mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
     }
 
     @Test
@@ -69,4 +95,128 @@
         verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
                 any(), any());
     }
-}
\ No newline at end of file
+
+    @Test
+    public void onMeasure_usesFullWidthWithoutOneHandedMode() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesFullWidthWithDeviceFlagDisabled() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
+                ONE_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesFullWidthWithSysUIFlagDisabled() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesHalfWidthWithFlagsEnabled() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
+                ONE_HANDED_SECURITY_MODE);
+
+        int halfWidthMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY);
+        mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+
+        verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesFullWidthForFullScreenIme() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
+                TWO_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_respectsViewInsets() {
+        int imeInsetAmount = 100;
+        int systemBarInsetAmount = 10;
+
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+        Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+        WindowInsets insets = new WindowInsets.Builder()
+                .setInsets(ime(), imeInset)
+                .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+                .build();
+
+        // It's reduced by the max of the systembar and IME, so just subtract IME inset.
+        int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                SCREEN_WIDTH - imeInsetAmount, View.MeasureSpec.EXACTLY);
+
+        mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec);
+    }
+
+    @Test
+    public void onMeasure_respectsViewInsets_largerSystembar() {
+        int imeInsetAmount = 0;
+        int systemBarInsetAmount = 10;
+
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+        Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+        WindowInsets insets = new WindowInsets.Builder()
+                .setInsets(ime(), imeInset)
+                .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+                .build();
+
+        int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                SCREEN_WIDTH - systemBarInsetAmount, View.MeasureSpec.EXACTLY);
+
+        mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec);
+    }
+
+    private void setUpKeyguard(
+            boolean deviceConfigCanUseOneHandedKeyguard,
+            boolean sysuiResourceCanUseOneHandedKeyguard,
+            SecurityMode securityMode) {
+        TestableResources testableResources = mContext.getOrCreateTestableResources();
+        testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard,
+                deviceConfigCanUseOneHandedKeyguard);
+        testableResources.addOverride(R.bool.can_use_one_handed_bouncer,
+                sysuiResourceCanUseOneHandedKeyguard);
+        mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 700f101..fb778e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -242,9 +242,18 @@
     }
 
     @Test
-    public void registersViewForCallbacks() throws RemoteException {
+    public void registersAndUnregistersViewForCallbacks() throws RemoteException {
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+        mFgExecutor.runAllReady();
         verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
         verify(mStatusBar).addExpansionChangedListener(
                 mUdfpsController.mStatusBarExpansionListener);
+
+        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+        mFgExecutor.runAllReady();
+        verify(mStatusBarStateController).removeCallback(mUdfpsController.mStatusBarStateListener);
+        verify(mStatusBar).removeExpansionChangedListener(
+                mUdfpsController.mStatusBarExpansionListener);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index 3d53062..62cc9b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -49,7 +49,7 @@
         MockitoAnnotations.initMocks(this);
 
         TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
-                new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
+                new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake(), /* qsFlag */false));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileBaseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileBaseViewTest.kt
new file mode 100644
index 0000000..998e070
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileBaseViewTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tileimpl
+
+import android.service.quicksettings.Tile
+import android.testing.AndroidTestingRunner
+import android.text.TextUtils
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSIconView
+import com.android.systemui.plugins.qs.QSTile
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class QSTileBaseViewTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var iconView: QSIconView
+
+    private lateinit var tileView: QSTileBaseView
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        tileView = QSTileBaseView(context, iconView, false)
+    }
+
+    @Test
+    fun testSecondaryLabelNotModified_unavailable() {
+        val state = QSTile.State()
+        val testString = "TEST STRING"
+        state.state = Tile.STATE_UNAVAILABLE
+        state.secondaryLabel = testString
+
+        tileView.handleStateChanged(state)
+
+        assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
+    }
+
+    @Test
+    fun testSecondaryLabelNotModified_booleanInactive() {
+        val state = QSTile.BooleanState()
+        val testString = "TEST STRING"
+        state.state = Tile.STATE_INACTIVE
+        state.secondaryLabel = testString
+
+        tileView.handleStateChanged(state)
+
+        assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
+    }
+
+    @Test
+    fun testSecondaryLabelNotModified_booleanActive() {
+        val state = QSTile.BooleanState()
+        val testString = "TEST STRING"
+        state.state = Tile.STATE_ACTIVE
+        state.secondaryLabel = testString
+
+        tileView.handleStateChanged(state)
+
+        assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
+    }
+
+    @Test
+    fun testSecondaryLabelNotModified_availableNotBoolean_inactive() {
+        val state = QSTile.State()
+        state.state = Tile.STATE_INACTIVE
+        state.secondaryLabel = ""
+
+        tileView.handleStateChanged(state)
+
+        assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue()
+    }
+
+    @Test
+    fun testSecondaryLabelNotModified_availableNotBoolean_active() {
+        val state = QSTile.State()
+        state.state = Tile.STATE_ACTIVE
+        state.secondaryLabel = ""
+
+        tileView.handleStateChanged(state)
+
+        assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue()
+    }
+
+    @Test
+    fun testSecondaryLabelDescription_unavailable() {
+        val state = QSTile.State()
+        state.state = Tile.STATE_UNAVAILABLE
+        state.secondaryLabel = ""
+
+        tileView.handleStateChanged(state)
+
+        assertThat(state.secondaryLabel as CharSequence).isEqualTo(
+            context.getString(R.string.tile_unavailable)
+        )
+    }
+
+    @Test
+    fun testSecondaryLabelDescription_booleanInactive() {
+        val state = QSTile.BooleanState()
+        state.state = Tile.STATE_INACTIVE
+        state.secondaryLabel = ""
+
+        tileView.handleStateChanged(state)
+
+        assertThat(state.secondaryLabel as CharSequence).isEqualTo(
+            context.getString(R.string.switch_bar_off)
+        )
+    }
+
+    @Test
+    fun testSecondaryLabelDescription_booleanActive() {
+        val state = QSTile.BooleanState()
+        state.state = Tile.STATE_ACTIVE
+        state.secondaryLabel = ""
+
+        tileView.handleStateChanged(state)
+
+        assertThat(state.secondaryLabel as CharSequence).isEqualTo(
+            context.getString(R.string.switch_bar_on)
+        )
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index ffd747e..880c290 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -18,10 +18,12 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.os.Handler;
-import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -34,9 +36,9 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.settings.FakeSettings;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -60,8 +62,9 @@
     private QSLogger mQSLogger;
     @Mock
     private UserTracker mUserTracker;
+    @Mock
+    private ReduceBrightColorsController mReduceBrightColorsController;
 
-    private FakeSettings mFakeSettings;
     private TestableLooper mTestableLooper;
     private ReduceBrightColorsTile mTile;
 
@@ -72,24 +75,23 @@
         mTestableLooper = TestableLooper.get(this);
 
         when(mHost.getContext()).thenReturn(mContext);
-        mFakeSettings = new FakeSettings();
 
         mTile = new ReduceBrightColorsTile(
                 true,
+                mReduceBrightColorsController,
                 mHost,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
-                mQSLogger,
-                mUserTracker,
-                mFakeSettings
+                mQSLogger
         );
     }
 
     @Test
     public void testNotActive() {
+        when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
         mTile.refreshState();
         mTestableLooper.processAllMessages();
 
@@ -100,33 +102,27 @@
 
     @Test
     public void testActive() {
-        mFakeSettings.putIntForUser(
-                Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
-                1,
-                mUserTracker.getUserId());
+        when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(true);
         mTile.refreshState();
         mTestableLooper.processAllMessages();
 
-        assertActiveState();
+        assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+        assertEquals(mTile.getState().label.toString(),
+                mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
     }
 
     @Test
-    public void testActive_clicked_isActive() {
+    public void testActive_clicked_featureIsActivated() {
+        when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
         mTile.refreshState();
         mTestableLooper.processAllMessages();
         // Validity check
         assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
 
         mTile.handleClick();
-        mTile.refreshState();
-        mTestableLooper.processAllMessages();
 
-        assertActiveState();
+        verify(mReduceBrightColorsController, times(1))
+                .setReduceBrightColorsActivated(eq(true));
     }
 
-    private void assertActiveState() {
-        assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
-        assertEquals(mTile.getState().label.toString(),
-                mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 71f146b..f31639c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -35,6 +35,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
@@ -121,4 +122,13 @@
         assertEquals("Transparent backgrounds should fallback to drawable color",
                 color, mIconView.getStaticDrawableColor());
     }
+
+    @Test
+    public void testGiantImageNotAllowed() {
+        Bitmap largeBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
+        Icon icon = Icon.createWithBitmap(largeBitmap);
+        StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+                icon, 0, 0, "");
+        assertFalse(mIconView.set(largeIcon));
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 82d1f43..094a70e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -47,6 +49,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
@@ -67,6 +70,8 @@
 import java.util.Collections;
 import java.util.List;
 
+import javax.inject.Named;
+
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -88,9 +93,11 @@
     @Mock private DataSaverController mDataSaverController;
     @Mock private ManagedProfileController mManagedProfileController;
     @Mock private NightDisplayListener mNightDisplayListener;
+    @Mock private ReduceBrightColorsController mReduceBrightColorsController;
     @Mock(answer = Answers.RETURNS_SELF)
     private AutoAddTracker.Builder mAutoAddTrackerBuilder;
     @Mock private Context mUserContext;
+    private final boolean mIsReduceBrightColorsAvailable = true;
 
     private AutoTileManager mAutoTileManager;
     private SecureSettings mSecureSettings;
@@ -130,7 +137,9 @@
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
             NightDisplayListener nightDisplayListener,
-            CastController castController) {
+            CastController castController,
+            ReduceBrightColorsController reduceBrightColorsController,
+            @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
         return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost,
                 Handler.createAsync(TestableLooper.get(this).getLooper()),
                 mSecureSettings,
@@ -138,13 +147,15 @@
                 dataSaverController,
                 managedProfileController,
                 nightDisplayListener,
-                castController);
+                castController,
+                reduceBrightColorsController,
+                isReduceBrightColorsAvailable);
     }
 
     private AutoTileManager createAutoTileManager(Context context) {
         return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController,
                 mDataSaverController, mManagedProfileController, mNightDisplayListener,
-                mCastController);
+                mCastController, mReduceBrightColorsController, mIsReduceBrightColorsAvailable);
     }
 
     @Test
@@ -157,9 +168,11 @@
         ManagedProfileController mPC = mock(ManagedProfileController.class);
         NightDisplayListener nDS = mock(NightDisplayListener.class);
         CastController cC = mock(CastController.class);
+        ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class);
 
         AutoTileManager manager =
-                createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC);
+                createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC, rBC,
+                        true);
 
         verify(tracker, never()).initialize();
         verify(hC, never()).addCallback(any());
@@ -167,6 +180,7 @@
         verify(mPC, never()).addCallback(any());
         verify(nDS, never()).setCallback(any());
         verify(cC, never()).addCallback(any());
+        verify(rBC, never()).addCallback(any());
         assertNull(manager.getSecureSettingForKey(TEST_SETTING));
         assertNull(manager.getSecureSettingForKey(TEST_SETTING_COMPONENT));
     }
@@ -207,6 +221,10 @@
             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
         }
 
+        InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController);
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any());
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any());
+
         InOrder inOrderCast = inOrder(mCastController);
         inOrderCast.verify(mCastController).removeCallback(any());
         inOrderCast.verify(mCastController).addCallback(any());
@@ -247,6 +265,10 @@
             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
         }
 
+        InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController);
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any());
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any());
+
         InOrder inOrderCast = inOrder(mCastController);
         inOrderCast.verify(mCastController).removeCallback(any());
         inOrderCast.verify(mCastController, never()).addCallback(any());
@@ -315,6 +337,18 @@
         verify(mQsTileHost, never()).addTile("night");
     }
 
+    @Test
+    public void reduceBrightColorsTileAdded_whenActivated() {
+        mAutoTileManager.mReduceBrightColorsCallback.onActivated(true);
+        verify(mQsTileHost).addTile("reduce_brightness");
+    }
+
+    @Test
+    public void reduceBrightColorsTileNotAdded_whenDeactivated() {
+        mAutoTileManager.mReduceBrightColorsCallback.onActivated(false);
+        verify(mQsTileHost, never()).addTile("reduce_brightness");
+    }
+
     private static List<CastDevice> buildFakeCastDevice(boolean isCasting) {
         CastDevice cd = new CastDevice();
         cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index dd31f52..ec5114e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -71,10 +71,8 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.MediaHierarchyManager;
@@ -222,10 +220,6 @@
     @Mock
     private FeatureFlags mFeatureFlags;
     @Mock
-    private ControlsComponent mControlsComponent;
-    @Mock
-    private BroadcastDispatcher mBroadcastDispatcher;
-    @Mock
     private AmbientState mAmbientState;
     @Mock
     private UserManager mUserManager;
@@ -328,9 +322,7 @@
                 mUserManager,
                 mMediaDataManager,
                 mAmbientState,
-                mFeatureFlags,
-                mControlsComponent,
-                mBroadcastDispatcher);
+                mFeatureFlags);
         mNotificationPanelViewController.initDependencies(
                 mStatusBar,
                 mNotificationShelfController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index e52b926..b1b71cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -372,6 +372,8 @@
                         new NetworkCapabilities(mNetCapabilities), new LinkProperties(), false);
                 mNetworkCallback.onCapabilitiesChanged(
                         mock(Network.class), new NetworkCapabilities(mNetCapabilities));
+                mDefaultCallbackInWifiTracker.onCapabilitiesChanged(
+                        mock(Network.class), new NetworkCapabilities(mNetCapabilities));
             } else {
                 mNetworkCallback.onLost(mock(Network.class));
             }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index c6812a2..847030e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -223,13 +223,14 @@
         setWifiEnabled(true);
         verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
 
+        mNetworkController.setNoNetworksAvailable(false);
         setWifiStateForVcn(true, testSsid);
         setWifiLevelForVcn(0);
-
         // Connected, but still not validated - does not show
         //verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
-        verifyLastMobileDataIndicatorsForVcn(false, 0, TelephonyIcons.ICON_CWF, false);
+        verifyLastMobileDataIndicatorsForVcn(false, 0, 0, false);
 
+        mNetworkController.setNoNetworksAvailable(true);
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
             setWifiLevelForVcn(testLevel);
 
@@ -239,7 +240,7 @@
 
             setConnectivityViaBroadcastForVcn(
                     NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo);
-            verifyLastMobileDataIndicatorsForVcn(false, testLevel, TelephonyIcons.ICON_CWF, false);
+            verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index d80c40f..8a0ac11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -19,13 +19,13 @@
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_NEUTRAL_PALETTE;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
-import static com.android.systemui.theme.ThemeOverlayController.USE_LOCK_SCREEN_WALLPAPER;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -33,6 +33,8 @@
 
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
 import android.content.om.FabricatedOverlay;
 import android.content.om.OverlayIdentifier;
 import android.graphics.Color;
@@ -91,7 +93,7 @@
     @Mock
     private FeatureFlags mFeatureFlags;
     @Captor
-    private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
+    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
     @Captor
     private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener;
 
@@ -114,12 +116,10 @@
         };
 
         mThemeOverlayController.start();
-        if (USE_LOCK_SCREEN_WALLPAPER) {
-            verify(mKeyguardStateController).addCallback(
-                    mKeyguardStateControllerCallback.capture());
-        }
         verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
                 eq(UserHandle.USER_ALL));
+        verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(),
+                eq(mMainExecutor), any());
         verify(mDumpManager).registerDumpable(any(), any());
     }
 
@@ -129,7 +129,6 @@
         verify(mBgExecutor).execute(registrationRunnable.capture());
 
         registrationRunnable.getValue().run();
-        verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_LOCK));
         verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
     }
 
@@ -156,6 +155,18 @@
         // Should not ask again if changed to same value
         mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
         verifyNoMoreInteractions(mThemeOverlayApplier);
+
+        // Should not ask again even for new colors until we change wallpapers
+        mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
+                null, null), WallpaperManager.FLAG_SYSTEM);
+        verifyNoMoreInteractions(mThemeOverlayApplier);
+
+        // But should change theme after changing wallpapers
+        clearInvocations(mThemeOverlayApplier);
+        mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+        mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
+                null, null), WallpaperManager.FLAG_SYSTEM);
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
     }
 
     @Test
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 065e2bb..88e6b66 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -102,6 +102,10 @@
         FingerprintGestureDispatcher.FingerprintGestureClient {
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "AbstractAccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CONNECTION =
+            LOG_TAG + ".IAccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CLIENT =
+            LOG_TAG + ".IAccessibilityServiceClient";
     private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
 
     protected static final String TAKE_SCREENSHOT = "takeScreenshot";
@@ -127,6 +131,7 @@
     protected final Object mLock;
 
     protected final AccessibilitySecurityPolicy mSecurityPolicy;
+    protected final AccessibilityTrace mTrace;
 
     // The service that's bound to this instance. Whenever this value is non-null, this
     // object is registered as a death recipient
@@ -247,7 +252,7 @@
     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
-            WindowManagerInternal windowManagerInternal,
+            AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
             SystemActionPerformer systemActionPerfomer,
             AccessibilityWindowManager a11yWindowManager) {
         mContext = context;
@@ -259,6 +264,7 @@
         mSecurityPolicy = securityPolicy;
         mSystemActionPerformer = systemActionPerfomer;
         mSystemSupport = systemSupport;
+        mTrace = trace;
         mMainHandler = mainHandler;
         mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
         mA11yWindowManager = a11yWindowManager;
@@ -291,6 +297,10 @@
             return false;
         }
         try {
+            if (mTrace.isA11yTracingEnabled()) {
+                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onKeyEvent",
+                        keyEvent + ", " + sequenceNumber);
+            }
             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
         } catch (RemoteException e) {
             return false;
@@ -354,11 +364,18 @@
 
     @Override
     public void setOnKeyEventResult(boolean handled, int sequence) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setOnKeyEventResult",
+                    "handled=" + handled + ";sequence=" + sequence);
+        }
         mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
     }
 
     @Override
     public AccessibilityServiceInfo getServiceInfo() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getServiceInfo");
+        }
         synchronized (mLock) {
             return mAccessibilityServiceInfo;
         }
@@ -375,6 +392,9 @@
 
     @Override
     public void setServiceInfo(AccessibilityServiceInfo info) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setServiceInfo", "info=" + info);
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
@@ -400,6 +420,9 @@
     @Nullable
     @Override
     public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindows");
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return null;
@@ -434,6 +457,9 @@
 
     @Override
     public AccessibilityWindowInfo getWindow(int windowId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindow", "windowId=" + windowId);
+        }
         synchronized (mLock) {
             int displayId = Display.INVALID_DISPLAY;
             if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
@@ -469,6 +495,13 @@
             long accessibilityNodeId, String viewIdResName, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByViewId",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                    + accessibilityNodeId + ";viewIdResName=" + viewIdResName + ";interactionId="
+                    + interactionId + ";callback=" + callback + ";interrogatingTid="
+                    + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -530,6 +563,12 @@
             long accessibilityNodeId, String text, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByText",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                    + accessibilityNodeId + ";text=" + text + ";interactionId=" + interactionId
+                    + ";callback=" + callback + ";interrogatingTid=" + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -591,6 +630,14 @@
             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             long interrogatingTid, Bundle arguments) throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(
+                    TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfoByAccessibilityId",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";interactionId=" + interactionId + ";callback="
+                            + callback + ";flags=" + flags + ";interrogatingTid=" + interrogatingTid
+                            + ";arguments=" + arguments);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -652,6 +699,13 @@
             int focusType, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findFocus",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";focusType=" + focusType + ";interactionId="
+                            + interactionId + ";callback=" + callback + ";interrogatingTid="
+                            + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -713,6 +767,13 @@
             int direction, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".focusSearch",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";direction=" + direction + ";interactionId="
+                            + interactionId + ";callback=" + callback + ";interrogatingTid="
+                            + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -770,10 +831,18 @@
 
     @Override
     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".sendGesture",
+                    "sequence=" + sequence + ";gestureSteps=" + gestureSteps);
+        }
     }
 
     @Override
     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".dispatchGesture", "sequence="
+                    + sequence + ";gestureSteps=" + gestureSteps + ";displayId=" + displayId);
+        }
     }
 
     @Override
@@ -781,6 +850,13 @@
             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performAccessibilityAction",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";action=" + action + ";arguments=" + arguments
+                            + ";interactionId=" + interactionId + ";callback=" + callback
+                            + ";interrogatingTid=" + interrogatingTid);
+        }
         final int resolvedWindowId;
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -802,6 +878,10 @@
 
     @Override
     public boolean performGlobalAction(int action) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performGlobalAction",
+                    "action=" + action);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -812,6 +892,9 @@
 
     @Override
     public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSystemActions");
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return Collections.emptyList();
@@ -822,6 +905,10 @@
 
     @Override
     public boolean isFingerprintGestureDetectionAvailable() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(
+                    TRACE_A11Y_SERVICE_CONNECTION + ".isFingerprintGestureDetectionAvailable");
+        }
         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
             return false;
         }
@@ -835,6 +922,10 @@
 
     @Override
     public float getMagnificationScale(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationScale",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return 1.0f;
@@ -850,6 +941,10 @@
 
     @Override
     public Region getMagnificationRegion(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationRegion",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             final Region region = Region.obtain();
             if (!hasRightsToCurrentUserLocked()) {
@@ -874,6 +969,10 @@
 
     @Override
     public float getMagnificationCenterX(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterX",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return 0.0f;
@@ -896,6 +995,10 @@
 
     @Override
     public float getMagnificationCenterY(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterY",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return 0.0f;
@@ -928,6 +1031,10 @@
 
     @Override
     public boolean resetMagnification(int displayId, boolean animate) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".resetMagnification",
+                    "displayId=" + displayId + ";animate=" + animate);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -950,6 +1057,11 @@
     @Override
     public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
             float centerY, boolean animate) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationScaleAndCenter",
+                    "displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
+                            + ";centerY=" + centerY + ";animate=" + animate);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -974,6 +1086,10 @@
 
     @Override
     public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationCallbackEnabled",
+                    "displayId=" + displayId + ";enabled=" + enabled);
+        }
         mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
     }
 
@@ -983,11 +1099,19 @@
 
     @Override
     public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardCallbackEnabled",
+                    "enabled=" + enabled);
+        }
         mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
     }
 
     @Override
     public void takeScreenshot(int displayId, RemoteCallback callback) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".takeScreenshot",
+                    "displayId=" + displayId + ";callback=" + callback);
+        }
         final long currentTimestamp = SystemClock.uptimeMillis();
         if (mRequestTakeScreenshotTimestampMs != 0
                 && (currentTimestamp - mRequestTakeScreenshotTimestampMs)
@@ -1157,6 +1281,10 @@
      */
     @Override
     public IBinder getOverlayWindowToken(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getOverlayWindowToken",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             return mOverlayWindowTokens.get(displayId);
         }
@@ -1170,6 +1298,10 @@
      */
     @Override
     public int getWindowIdForLeashToken(@NonNull IBinder token) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindowIdForLeashToken",
+                    "token=" + token);
+        }
         synchronized (mLock) {
             return mA11yWindowManager.getWindowIdLocked(token);
         }
@@ -1181,6 +1313,9 @@
             // Clear the proxy in the other process so this
             // IAccessibilityServiceConnection can be garbage collected.
             if (mServiceInterface != null) {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", "null, " + mId + ", null");
+                }
                 mServiceInterface.init(null, mId, null);
             }
         } catch (RemoteException re) {
@@ -1329,6 +1464,10 @@
         }
 
         try {
+            if (mTrace.isA11yTracingEnabled()) {
+                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityEvent",
+                        event + ";" + serviceWantsEvent);
+            }
             listener.onAccessibilityEvent(event, serviceWantsEvent);
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
@@ -1382,6 +1521,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onMagnificationChanged", displayId
+                            + ", " + region + ", " + scale + ", " + centerX + ", " + centerY);
+                }
                 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
@@ -1397,6 +1540,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSoftKeyboardShowModeChanged",
+                            String.valueOf(showState));
+                }
                 listener.onSoftKeyboardShowModeChanged(showState);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
@@ -1409,6 +1556,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonClicked",
+                            String.valueOf(displayId));
+                }
                 listener.onAccessibilityButtonClicked(displayId);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
@@ -1427,6 +1578,11 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(
+                            TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonAvailabilityChanged",
+                            String.valueOf(available));
+                }
                 listener.onAccessibilityButtonAvailabilityChanged(available);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG,
@@ -1440,6 +1596,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onGesture",
+                            gestureInfo.toString());
+                }
                 listener.onGesture(gestureInfo);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo
@@ -1452,6 +1612,9 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSystemActionsChanged");
+                }
                 listener.onSystemActionsChanged();
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending system actions change to " + mService,
@@ -1464,6 +1627,9 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".clearAccessibilityCache");
+                }
                 listener.clearAccessibilityCache();
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
@@ -1790,14 +1956,27 @@
 
     @Override
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setGestureDetectionPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
         mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
     }
 
     @Override
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setTouchExplorationPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
         mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
     }
 
     @Override
-    public void setFocusAppearance(int strokeWidth, int color) { }
+    public void setFocusAppearance(int strokeWidth, int color) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setFocusAppearance",
+                    "strokeWidth=" + strokeWidth + ";color=" + color);
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c63c2e1..b3be044 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -149,6 +149,7 @@
  */
 public class AccessibilityManagerService extends IAccessibilityManager.Stub
         implements AbstractAccessibilityServiceConnection.SystemSupport,
+        AccessibilityTrace,
         AccessibilityUserState.ServiceInfoChangeListener,
         AccessibilityWindowManager.AccessibilityEventSender,
         AccessibilitySecurityPolicy.AccessibilityUserManager,
@@ -243,6 +244,7 @@
     final SparseArray<AccessibilityUserState> mUserStates = new SparseArray<>();
 
     private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock);
+    private final WindowManagerInternal.AccessibilityControllerInternal mA11yController;
 
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
 
@@ -288,6 +290,7 @@
         mContext = context;
         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+        mA11yController = mWindowManagerService.getAccessibilityController();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = packageManager;
@@ -308,6 +311,7 @@
         mContext = context;
         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+        mA11yController = mWindowManagerService.getAccessibilityController();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = mContext.getPackageManager();
@@ -328,16 +332,25 @@
 
     @Override
     public int getCurrentUserIdLocked() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getCurrentUserIdLocked");
+        }
         return mCurrentUserId;
     }
 
     @Override
     public boolean isAccessibilityButtonShown() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".isAccessibilityButtonShown");
+        }
         return mIsAccessibilityButtonShown;
     }
 
     @Override
     public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".onServiceInfoChangedLocked", "userState=" + userState);
+        }
         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
     }
 
@@ -395,6 +408,10 @@
         PackageMonitor monitor = new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onSomePackagesChanged");
+                }
+
                 synchronized (mLock) {
                     // Only the profile parent can install accessibility services.
                     // Therefore we ignore packages from linked profiles.
@@ -419,6 +436,10 @@
                 // mBindingServices in binderDied() during updating. Remove services from  this
                 // package from mBindingServices, and then update the user state to re-bind new
                 // versions of them.
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onPackageUpdateFinished",
+                            "packageName=" + packageName + ";uid=" + uid);
+                }
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
                     if (userId != mCurrentUserId) {
@@ -448,6 +469,11 @@
 
             @Override
             public void onPackageRemoved(String packageName, int uid) {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onPackageRemoved",
+                            "packageName=" + packageName + ";uid=" + uid);
+                }
+
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
                     // Only the profile parent can install accessibility services.
@@ -487,6 +513,10 @@
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages,
                     int uid, boolean doit) {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onHandleForceStop", "intent=" + intent + ";packages="
+                            + packages + ";uid=" + uid + ";doit=" + doit);
+                }
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
                     // Only the profile parent can install accessibility services.
@@ -533,6 +563,10 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".BR.onReceive", "context=" + context + ";intent=" + intent);
+                }
+
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
@@ -616,6 +650,10 @@
 
     @Override
     public long addClient(IAccessibilityManagerClient callback, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".addClient", "callback=" + callback + ";userId=" + userId);
+        }
+
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -654,6 +692,9 @@
 
     @Override
     public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".sendAccessibilityEvent", "event=" + event + ";userId=" + userId);
+        }
         boolean dispatchEvent = false;
 
         synchronized (mLock) {
@@ -746,6 +787,10 @@
      */
     @Override
     public void registerSystemAction(RemoteAction action, int actionId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".registerSystemAction", "action=" + action + ";actionId="
+                    + actionId);
+        }
         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
         getSystemActionPerformer().registerSystemAction(actionId, action);
     }
@@ -757,6 +802,9 @@
      */
     @Override
     public void unregisterSystemAction(int actionId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".unregisterSystemAction", "actionId=" + actionId);
+        }
         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
         getSystemActionPerformer().unregisterSystemAction(actionId);
     }
@@ -771,6 +819,10 @@
 
     @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList", "userId=" + userId);
+        }
+
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -788,6 +840,11 @@
     @Override
     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
             int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList",
+                    "feedbackType=" + feedbackType + ";userId=" + userId);
+        }
+
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -816,6 +873,10 @@
 
     @Override
     public void interrupt(int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".interrupt", "userId=" + userId);
+        }
+
         List<IAccessibilityServiceClient> interfacesToInterrupt;
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
@@ -842,6 +903,9 @@
         }
         for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
             try {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt");
+                }
                 interfacesToInterrupt.get(i).onInterrupt();
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending interrupt request to "
@@ -854,18 +918,31 @@
     public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken,
             IAccessibilityInteractionConnection connection, String packageName,
             int userId) throws RemoteException {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".addAccessibilityInteractionConnection",
+                    "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection="
+                            + connection + "; packageName=" + packageName + ";userId=" + userId);
+        }
+
         return mA11yWindowManager.addAccessibilityInteractionConnection(
                 windowToken, leashToken, connection, packageName, userId);
     }
 
     @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection", "window=" + window);
+        }
         mA11yWindowManager.removeAccessibilityInteractionConnection(window);
     }
 
     @Override
     public void setPictureInPictureActionReplacingConnection(
             IAccessibilityInteractionConnection connection) throws RemoteException {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection",
+                    "connection=" + connection);
+        }
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.MODIFY_ACCESSIBILITY_DATA,
                 SET_PIP_ACTION_REPLACEMENT);
         mA11yWindowManager.setPictureInPictureActionReplacingConnection(connection);
@@ -876,13 +953,19 @@
             IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo,
             int flags) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".registerUiTestAutomationService", "owner=" + owner
+                    + ";serviceClient=" + serviceClient + ";accessibilityServiceInfo="
+                    + accessibilityServiceInfo + ";flags=" + flags);
+        }
+
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
 
         synchronized (mLock) {
             mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient,
                     mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler,
-                    mSecurityPolicy, this, mWindowManagerService, getSystemActionPerformer(),
+                    mSecurityPolicy, this, this, mWindowManagerService, getSystemActionPerformer(),
                     mA11yWindowManager, flags);
             onUserStateChangedLocked(getCurrentUserStateLocked());
         }
@@ -890,6 +973,10 @@
 
     @Override
     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".unregisterUiTestAutomationService",
+                    "serviceClient=" + serviceClient);
+        }
         synchronized (mLock) {
             mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient);
         }
@@ -898,6 +985,11 @@
     @Override
     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
             ComponentName service, boolean touchExplorationEnabled) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".temporaryEnableAccessibilityStateUntilKeyguardRemoved",
+                    "service=" + service + ";touchExplorationEnabled=" + touchExplorationEnabled);
+        }
+
         mSecurityPolicy.enforceCallingPermission(
                 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
                 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
@@ -926,6 +1018,10 @@
 
     @Override
     public IBinder getWindowToken(int windowId, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getWindowToken", "windowId=" + windowId + ";userId=" + userId);
+        }
+
         mSecurityPolicy.enforceCallingPermission(
                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
                 GET_WINDOW_TOKEN);
@@ -965,6 +1061,11 @@
      */
     @Override
     public void notifyAccessibilityButtonClicked(int displayId, String targetName) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked",
+                    "displayId=" + displayId + ";targetName=" + targetName);
+        }
+
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller does not hold permission "
@@ -990,6 +1091,10 @@
      */
     @Override
     public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged", "shown=" + shown);
+        }
+
         mSecurityPolicy.enforceCallingOrSelfPermission(
                 android.Manifest.permission.STATUS_BAR_SERVICE);
         synchronized (mLock) {
@@ -1018,6 +1123,10 @@
      */
     @Override
     public void onSystemActionsChanged() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".onSystemActionsChanged");
+        }
+
         synchronized (mLock) {
             AccessibilityUserState state = getCurrentUserStateLocked();
             notifySystemActionsChangedLocked(state);
@@ -1080,6 +1189,10 @@
 
     @Override
     public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getMotionEventInjectorForDisplayLocked", "displayId=" + displayId);
+        }
+
         final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
         MotionEventInjector motionEventInjector = null;
         while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
@@ -1646,6 +1759,11 @@
     @Override
     public void persistComponentNamesToSettingLocked(String settingName,
             Set<ComponentName> componentNames, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".persistComponentNamesToSettingLocked", "settingName=" + settingName
+                    + ";componentNames=" + componentNames + ";userId=" + userId);
+        }
+
         persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames,
                 componentName -> componentName.flattenToShortString());
     }
@@ -1730,7 +1848,7 @@
                 if (service == null) {
                     service = new AccessibilityServiceConnection(userState, mContext, componentName,
                             installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
-                            this, mWindowManagerService, getSystemActionPerformer(),
+                            this, this, mWindowManagerService, getSystemActionPerformer(),
                             mA11yWindowManager, mActivityTaskManagerService);
                 } else if (userState.mBoundServices.contains(service)) {
                     continue;
@@ -2607,6 +2725,10 @@
     @GuardedBy("mLock")
     @Override
     public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getCompatibleMagnificationSpecLocked", "windowId=" + windowId);
+        }
+
         IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
                 mCurrentUserId, windowId);
         if (windowToken != null) {
@@ -2618,6 +2740,10 @@
 
     @Override
     public KeyEventDispatcher getKeyEventDispatcher() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getKeyEventDispatcher");
+        }
+
         if (mKeyEventDispatcher == null) {
             mKeyEventDispatcher = new KeyEventDispatcher(
                     mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock,
@@ -2630,6 +2756,12 @@
     @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
     public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
             int flags) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getPendingIntentActivity", "context=" + context + ";requestCode="
+                    + requestCode + ";intent=" + intent + ";flags=" + flags);
+        }
+
+
         return PendingIntent.getActivity(context, requestCode, intent, flags);
     }
 
@@ -2644,6 +2776,10 @@
      */
     @Override
     public void performAccessibilityShortcut(String targetName) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".performAccessibilityShortcut", "targetName=" + targetName);
+        }
+
         if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)
                 && (mContext.checkCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
                 != PackageManager.PERMISSION_GRANTED)) {
@@ -2828,6 +2964,10 @@
 
     @Override
     public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getAccessibilityShortcutTargets", "shortcutType=" + shortcutType);
+        }
+
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException(
@@ -2897,6 +3037,10 @@
 
     @Override
     public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".sendAccessibilityEventForCurrentUserLocked", "event=" + event);
+        }
+
         sendAccessibilityEventLocked(event, mCurrentUserId);
     }
 
@@ -2918,6 +3062,10 @@
      */
     @Override
     public boolean sendFingerprintGesture(int gestureKeyCode) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".sendFingerprintGesture", "gestureKeyCode=" + gestureKeyCode);
+        }
+
         synchronized(mLock) {
             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
                 throw new SecurityException("Only SYSTEM can call sendFingerprintGesture");
@@ -2939,6 +3087,10 @@
      */
     @Override
     public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getAccessibilityWindowId", "windowToken=" + windowToken);
+        }
+
         synchronized (mLock) {
             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
                 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId");
@@ -2956,6 +3108,10 @@
      */
     @Override
     public long getRecommendedTimeoutMillis() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getRecommendedTimeoutMillis");
+        }
+
         synchronized(mLock) {
             final AccessibilityUserState userState = getCurrentUserStateLocked();
             return getRecommendedTimeoutMillisLocked(userState);
@@ -2970,6 +3126,10 @@
     @Override
     public void setWindowMagnificationConnection(
             IWindowMagnificationConnection connection) throws RemoteException {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setWindowMagnificationConnection", "connection=" + connection);
+        }
+
         mSecurityPolicy.enforceCallingOrSelfPermission(
                 android.Manifest.permission.STATUS_BAR_SERVICE);
 
@@ -3000,6 +3160,11 @@
 
     @Override
     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".associateEmbeddedHierarchy",
+                    "host=" + host + ";embedded=" + embedded);
+        }
+
         synchronized (mLock) {
             mA11yWindowManager.associateEmbeddedHierarchyLocked(host, embedded);
         }
@@ -3007,6 +3172,10 @@
 
     @Override
     public void disassociateEmbeddedHierarchy(@NonNull IBinder token) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy", "token=" + token);
+        }
+
         synchronized (mLock) {
             mA11yWindowManager.disassociateEmbeddedHierarchyLocked(token);
         }
@@ -3084,6 +3253,9 @@
 
     @Override
     public FullScreenMagnificationController getFullScreenMagnificationController() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getFullScreenMagnificationController");
+        }
         synchronized (mLock) {
             return mMagnificationController.getFullScreenMagnificationController();
         }
@@ -3091,6 +3263,10 @@
 
     @Override
     public void onClientChangeLocked(boolean serviceInfoChanged) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".onClientChangeLocked", "serviceInfoChanged=" + serviceInfoChanged);
+        }
+
         AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
         onUserStateChangedLocked(userState);
         if (serviceInfoChanged) {
@@ -3126,8 +3302,9 @@
             AccessibilityServiceConnection service = new AccessibilityServiceConnection(
                     userState, mContext,
                     COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
-                    AccessibilityManagerService.this, mWindowManagerService,
-                    getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) {
+                    AccessibilityManagerService.this, AccessibilityManagerService.this,
+                    mWindowManagerService, getSystemActionPerformer(), mA11yWindowManager,
+                    mActivityTaskManagerService) {
                 @Override
                 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
                     return true;
@@ -3614,6 +3791,11 @@
 
     @Override
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setGestureDetectionPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
+
         mMainHandler.sendMessage(
                 obtainMessage(
                         AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal,
@@ -3624,6 +3806,11 @@
 
     @Override
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setTouchExplorationPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
+
         mMainHandler.sendMessage(
                 obtainMessage(
                         AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal,
@@ -3661,4 +3848,20 @@
         });
 
     }
+
+    @Override
+    public boolean isA11yTracingEnabled() {
+        return mA11yController.isAccessibilityTracingEnabled();
+    }
+
+    @Override
+    public void logTrace(String where) {
+        logTrace(where, "");
+    }
+
+    @Override
+    public void logTrace(String where, String callingParams) {
+        mA11yController.logTrace(where, callingParams, "".getBytes(),
+                Binder.getCallingUid(), Thread.currentThread().getStackTrace());
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 6756268..7d75b73 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -53,6 +53,10 @@
  */
 class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
     private static final String LOG_TAG = "AccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CONNECTION =
+            LOG_TAG + ".IAccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CLIENT =
+            LOG_TAG + ".IAccessibilityServiceClient";
     /*
      Holding a weak reference so there isn't a loop of references. AccessibilityUserState keeps
      lists of bound and binding services. These are freed on user changes, but just in case it
@@ -70,11 +74,12 @@
             ComponentName componentName,
             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
-            WindowManagerInternal windowManagerInternal,
+            AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
             SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm,
             ActivityTaskManagerInternal activityTaskManagerService) {
         super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
-                securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer, awm);
+                securityPolicy, systemSupport, trace, windowManagerInternal, systemActionPerfomer,
+                awm);
         mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState);
         mIntent = new Intent().setComponent(mComponentName);
         mMainHandler = mainHandler;
@@ -132,6 +137,9 @@
 
     @Override
     public void disableSelf() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".disableSelf");
+        }
         synchronized (mLock) {
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState == null) return;
@@ -210,6 +218,10 @@
             return;
         }
         try {
+            if (mTrace.isA11yTracingEnabled()) {
+                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", this + ", " + mId + ", "
+                        + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
+            }
             serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
         } catch (RemoteException re) {
             Slog.w(LOG_TAG, "Error while setting connection for service: "
@@ -252,6 +264,10 @@
 
     @Override
     public boolean setSoftKeyboardShowMode(int showMode) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardShowMode",
+                    "showMode=" + showMode);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -264,12 +280,19 @@
 
     @Override
     public int getSoftKeyboardShowMode() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSoftKeyboardShowMode");
+        }
         final AccessibilityUserState userState = mUserStateWeakReference.get();
         return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0;
     }
 
     @Override
     public boolean switchToInputMethod(String imeId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".switchToInputMethod",
+                    "imeId=" + imeId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -288,6 +311,9 @@
 
     @Override
     public boolean isAccessibilityButtonAvailable() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".isAccessibilityButtonAvailable");
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -347,6 +373,10 @@
         }
         if (serviceInterface != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT
+                            + ".onFingerprintCapturingGesturesChanged", String.valueOf(active));
+                }
                 mServiceInterface.onFingerprintCapturingGesturesChanged(active);
             } catch (RemoteException e) {
             }
@@ -364,6 +394,10 @@
         }
         if (serviceInterface != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onFingerprintGesture",
+                            String.valueOf(gesture));
+                }
                 mServiceInterface.onFingerprintGesture(gesture);
             } catch (RemoteException e) {
             }
@@ -382,6 +416,10 @@
                             gestureSteps.getList(), mServiceInterface, sequence, displayId);
                 } else {
                     try {
+                        if (mTrace.isA11yTracingEnabled()) {
+                            mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onPerformGestureResult",
+                                    sequence + ", false");
+                        }
                         mServiceInterface.onPerformGestureResult(sequence, false);
                     } catch (RemoteException re) {
                         Slog.e(LOG_TAG, "Error sending motion event injection failure to "
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java
new file mode 100644
index 0000000..0c03877
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.accessibility;
+
+/**
+ * Interface to log accessibility trace.
+ */
+public interface AccessibilityTrace {
+    /**
+     * Whether the trace is enabled.
+     */
+    boolean isA11yTracingEnabled();
+
+    /**
+     * Log one trace entry.
+     * @param where A string to identify this log entry, which can be used to filter/search
+     *        through the tracing file.
+     */
+    void logTrace(String where);
+
+    /**
+     * Log one trace entry.
+     * @param where A string to identify this log entry, which can be used to filter/search
+     *        through the tracing file.
+     * @param callingParams The parameters for the method to be logged.
+     */
+    void logTrace(String where, String callingParams);
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 4473754..9547280 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -53,6 +53,8 @@
 
     private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport;
 
+    private AccessibilityTrace mTrace;
+
     private int mUiAutomationFlags;
 
     UiAutomationManager(Object lock) {
@@ -89,6 +91,7 @@
             int id, Handler mainHandler,
             AccessibilitySecurityPolicy securityPolicy,
             AbstractAccessibilityServiceConnection.SystemSupport systemSupport,
+            AccessibilityTrace trace,
             WindowManagerInternal windowManagerInternal,
             SystemActionPerformer systemActionPerformer,
             AccessibilityWindowManager awm, int flags) {
@@ -111,13 +114,14 @@
 
             mUiAutomationFlags = flags;
             mSystemSupport = systemSupport;
+            mTrace = trace;
             // Ignore registering UiAutomation if it is not allowed to use the accessibility
             // subsystem.
             if (!useAccessibility()) {
                 return;
             }
             mUiAutomationService = new UiAutomationService(context, accessibilityServiceInfo, id,
-                    mainHandler, mLock, securityPolicy, systemSupport, windowManagerInternal,
+                    mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal,
                     systemActionPerformer, awm);
             mUiAutomationServiceOwner = owner;
             mUiAutomationServiceInfo = accessibilityServiceInfo;
@@ -239,11 +243,12 @@
         UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo,
                 int id, Handler mainHandler, Object lock,
                 AccessibilitySecurityPolicy securityPolicy,
-                SystemSupport systemSupport, WindowManagerInternal windowManagerInternal,
+                SystemSupport systemSupport, AccessibilityTrace trace,
+                WindowManagerInternal windowManagerInternal,
                 SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm) {
             super(context, COMPONENT_NAME, accessibilityServiceInfo, id, mainHandler, lock,
-                    securityPolicy, systemSupport, windowManagerInternal, systemActionPerformer,
-                    awm);
+                    securityPolicy, systemSupport, trace, windowManagerInternal,
+                    systemActionPerformer, awm);
             mMainHandler = mainHandler;
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
index feed18d..3d8f5173 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
@@ -98,8 +98,7 @@
         }
         mProcessMotionEvent = true;
         for (int i = 0; i < mGestureMatchers.size(); i++) {
-            final GestureMatcher matcher =
-                    mGestureMatchers.get(i);
+            final GestureMatcher matcher = mGestureMatchers.get(i);
             matcher.onMotionEvent(event, rawEvent, policyFlags);
             if (matcher.getState() == GestureMatcher.STATE_GESTURE_COMPLETED) {
                 clear();
@@ -128,7 +127,10 @@
             MotionEvent rawEvent, int policyFlags) {
         if (state == GestureMatcher.STATE_GESTURE_COMPLETED) {
             mListener.onGestureCompleted(gestureId, event, rawEvent, policyFlags);
-            //Clear the states in onMotionEvent().
+            // Ideally we clear the states in onMotionEvent(), this case is for hold gestures.
+            // If we clear before processing up event , then MultiTap matcher cancels the gesture
+            // due to incorrect state. It ends up listener#onGestureCancelled is called even
+            // the gesture is detected.
             if (!mProcessMotionEvent) {
                 clear();
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
index 7a4d9e3..570e0ce 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
@@ -33,7 +33,7 @@
 class MagnificationGestureMatcher {
 
     private static final int GESTURE_BASE = 100;
-    public static final int GESTURE_TWO_FINGER_DOWN = GESTURE_BASE + 1;
+    public static final int GESTURE_TWO_FINGERS_DOWN_OR_SWIPE = GESTURE_BASE + 1;
     public static final int GESTURE_SWIPE = GESTURE_BASE + 2;
     public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3;
     public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4;
@@ -41,7 +41,7 @@
     public static final int GESTURE_TRIPLE_TAP_AND_HOLD = GESTURE_BASE + 6;
 
     @IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = {
-            GESTURE_TWO_FINGER_DOWN,
+            GESTURE_TWO_FINGERS_DOWN_OR_SWIPE,
             GESTURE_SWIPE
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -57,8 +57,8 @@
         switch (gestureId) {
             case GESTURE_SWIPE:
                 return "GESTURE_SWIPE";
-            case GESTURE_TWO_FINGER_DOWN:
-                return "GESTURE_TWO_FINGER_DOWN";
+            case GESTURE_TWO_FINGERS_DOWN_OR_SWIPE:
+                return "GESTURE_TWO_FINGERS_DOWN_OR_SWIPE";
             case GESTURE_SINGLE_TAP:
                 return "GESTURE_SINGLE_TAP";
             case GESTURE_SINGLE_TAP_AND_HOLD:
@@ -71,6 +71,12 @@
         return "none";
     }
 
+    /**
+     * @param context
+     * @return the duration in milliseconds between the first tap's down event and
+     * the second tap's down event to be considered that the user is going to performing
+     *  panning/scaling gesture.
+     */
     static int getMagnificationMultiTapTimeout(Context context) {
         return ViewConfiguration.getDoubleTapTimeout() + context.getResources().getInteger(
                 R.integer.config_screen_magnification_multi_tap_adjustment);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index a209086..085c343 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -65,7 +65,7 @@
          *                  the last event before timeout.
          *
          * @see MagnificationGestureMatcher#GESTURE_SWIPE
-         * @see MagnificationGestureMatcher#GESTURE_TWO_FINGER_DOWN
+         * @see MagnificationGestureMatcher#GESTURE_TWO_FINGERS_DOWN_OR_SWIPE
          */
         void onGestureCompleted(@GestureId int gestureId, long lastDownEventTime,
                 List<MotionEventInfo> delayedEventQueue, MotionEvent event);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java b/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
index cd5061f..fa15ac1 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
@@ -49,6 +49,11 @@
     }
 
     @Override
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
     protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (gestureMatched(event, rawEvent, policyFlags)) {
             completeGesture(event, rawEvent, policyFlags);
@@ -65,7 +70,7 @@
     }
 
     private boolean gestureMatched(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        return mLastDown != null && (distance(mLastDown, event) >= mSwipeMinDistance);
+        return mLastDown != null && (distance(mLastDown, event) > mSwipeMinDistance);
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java
deleted file mode 100644
index 173a5b8..0000000
--- a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.accessibility.magnification;
-
-import android.content.Context;
-import android.os.Handler;
-import android.view.MotionEvent;
-
-import com.android.server.accessibility.gestures.GestureMatcher;
-
-/**
- *
- * This class is responsible for matching two fingers down gestures. The gesture matching
- * result is determined in a duration.
- */
-final class TwoFingersDown extends GestureMatcher {
-
-    private MotionEvent mLastDown;
-    private final int mDetectionDurationMillis;
-
-    TwoFingersDown(Context context) {
-        super(MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN,
-                new Handler(context.getMainLooper()), null);
-        mDetectionDurationMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
-                context);
-    }
-
-    @Override
-    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        mLastDown = MotionEvent.obtain(event);
-        cancelAfter(mDetectionDurationMillis, event, rawEvent, policyFlags);
-    }
-
-    @Override
-    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        if (mLastDown == null) {
-            cancelGesture(event, rawEvent, policyFlags);
-        }
-        completeGesture(event, rawEvent, policyFlags);
-    }
-
-    @Override
-    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        cancelGesture(event, rawEvent, policyFlags);
-    }
-
-    @Override
-    public void clear() {
-        if (mLastDown != null) {
-            mLastDown.recycle();
-            mLastDown = null;
-        }
-        super.clear();
-    }
-
-    @Override
-    protected String getGestureName() {
-        return this.getClass().getSimpleName();
-    }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java
new file mode 100644
index 0000000..1742bd4
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility.magnification;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+import android.util.MathUtils;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.server.accessibility.gestures.GestureMatcher;
+
+/**
+ * This class is responsible for detecting that the user is using two fingers to perform
+ * swiping gestures or just stay pressed on the screen. The gesture matching result is determined
+ * in a duration.
+ */
+final class TwoFingersDownOrSwipe extends GestureMatcher {
+
+    private final int mDoubleTapTimeout;
+    private final int mDetectionDurationMillis;
+    private final int mSwipeMinDistance;
+    private MotionEvent mFirstPointerDown;
+    private MotionEvent mSecondPointerDown;
+
+    TwoFingersDownOrSwipe(Context context) {
+        super(MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE,
+                new Handler(context.getMainLooper()), null);
+        mDetectionDurationMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
+                context);
+        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+        mSwipeMinDistance = ViewConfiguration.get(context).getScaledTouchSlop();
+
+    }
+
+    @Override
+    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        mFirstPointerDown = MotionEvent.obtain(event);
+        cancelAfter(mDetectionDurationMillis, event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mFirstPointerDown == null) {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+        if (event.getPointerCount() == 2) {
+            mSecondPointerDown = MotionEvent.obtain(event);
+            completeAfter(mDoubleTapTimeout, event, rawEvent, policyFlags);
+        } else {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mFirstPointerDown == null || mSecondPointerDown == null) {
+            return;
+        }
+        if (distance(mFirstPointerDown, /* move */ event) > mSwipeMinDistance) {
+            completeGesture(event, rawEvent, policyFlags);
+            return;
+        }
+        if (distance(mSecondPointerDown, /* move */ event) > mSwipeMinDistance) {
+            // The second pointer is swiping.
+            completeGesture(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    public void clear() {
+        if (mFirstPointerDown != null) {
+            mFirstPointerDown.recycle();
+            mFirstPointerDown = null;
+        }
+        if (mSecondPointerDown != null) {
+            mSecondPointerDown.recycle();
+            mSecondPointerDown = null;
+        }
+        super.clear();
+    }
+
+    @Override
+    protected String getGestureName() {
+        return this.getClass().getSimpleName();
+    }
+
+    private static double distance(@NonNull MotionEvent downEvent, @NonNull MotionEvent moveEvent) {
+        final int downActionIndex = downEvent.getActionIndex();
+        final int downPointerId = downEvent.getPointerId(downActionIndex);
+        final int moveActionIndex = moveEvent.findPointerIndex(downPointerId);
+        if (moveActionIndex < 0) {
+            return -1;
+        }
+        return MathUtils.dist(downEvent.getX(downActionIndex), downEvent.getY(downActionIndex),
+                moveEvent.getX(moveActionIndex), moveEvent.getY(moveActionIndex));
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 55a911e..fa34062 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -323,7 +323,7 @@
      * manipulate the window magnifier or want to interact with current UI. The rule of leaving
      * this state is as follows:
      * <ol>
-     *   <li> If {@link MagnificationGestureMatcher#GESTURE_TWO_FINGER_DOWN} is detected,
+     *   <li> If {@link MagnificationGestureMatcher#GESTURE_TWO_FINGERS_DOWN_OR_SWIPE} is detected,
      *   {@link State} will be transited to {@link PanningScalingGestureState}.</li>
      *   <li> If other gesture is detected and the last motion event is neither ACTION_UP nor
      *   ACTION_CANCEL.
@@ -357,7 +357,7 @@
                     new SimpleSwipe(context),
                     multiTap,
                     multiTapAndHold,
-                    new TwoFingersDown(context));
+                    new TwoFingersDownOrSwipe(context));
         }
 
         @Override
@@ -399,7 +399,7 @@
                 Slog.d(mLogTag,
                         "onGestureDetected : delayedEventQueue = " + delayedEventQueue);
             }
-            if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN
+            if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE
                     && mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) {
                 transitionTo(mObservePanningScalingState);
             } else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 50ad661..e251700 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,6 +19,7 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.res.Resources.ID_NULL;
 
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
@@ -2578,9 +2579,9 @@
             info.updatePeriodMillis = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
             info.initialLayout = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, ID_NULL);
             info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
-                    AppWidgetProviderInfo_initialKeyguardLayout, 0);
+                    AppWidgetProviderInfo_initialKeyguardLayout, ID_NULL);
 
             String className = sa
                     .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
@@ -2591,11 +2592,12 @@
             info.label = activityInfo.loadLabel(pm).toString();
             info.icon = activityInfo.getIconResource();
             info.previewImage = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, ID_NULL);
             info.previewLayout = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, 0);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, ID_NULL);
             info.autoAdvanceViewId = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId,
+                    View.NO_ID);
             info.resizeMode = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
                     AppWidgetProviderInfo.RESIZE_NONE);
@@ -2605,8 +2607,7 @@
             info.widgetFeatures = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
             info.descriptionRes = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_description,
-                    Resources.ID_NULL);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_description, ID_NULL);
             sa.recycle();
             return info;
         } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 21cae45..a3a0cb4 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -1330,7 +1330,7 @@
         mPermissionControllerManager.getPrivilegesDescriptionStringForProfile(
                 deviceProfile, FgThread.getExecutor(), desc -> {
                         try {
-                            result.complete(desc);
+                            result.complete(String.valueOf(desc));
                         } catch (Exception e) {
                             result.completeExceptionally(e);
                         }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 0be485b..f4a8ccd 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -69,6 +69,7 @@
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
 import android.service.contentcapture.IDataShareCallback;
 import android.service.contentcapture.IDataShareReadAdapter;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Pair;
@@ -81,6 +82,7 @@
 import android.view.contentcapture.DataRemovalRequest;
 import android.view.contentcapture.DataShareRequest;
 import android.view.contentcapture.IContentCaptureManager;
+import android.view.contentcapture.IContentCaptureOptionsCallback;
 import android.view.contentcapture.IDataShareWriteAdapter;
 
 import com.android.internal.annotations.GuardedBy;
@@ -88,7 +90,6 @@
 import com.android.internal.infra.GlobalWhitelistState;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -101,6 +102,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -134,6 +136,9 @@
 
     private final LocalService mLocalService = new LocalService();
 
+    private final ContentCaptureManagerServiceStub mContentCaptureManagerServiceStub =
+            new ContentCaptureManagerServiceStub();
+
     @Nullable
     final LocalLog mRequestsHistory;
 
@@ -224,8 +229,7 @@
 
     @Override // from SystemService
     public void onStart() {
-        publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE,
-                new ContentCaptureManagerServiceStub());
+        publishBinderService(CONTENT_CAPTURE_MANAGER_SERVICE, mContentCaptureManagerServiceStub);
         publishLocalService(ContentCaptureManagerInternal.class, mLocalService);
     }
 
@@ -492,6 +496,19 @@
         }
     }
 
+    void updateOptions(String packageName, ContentCaptureOptions options) {
+        ArraySet<CallbackRecord> records;
+        synchronized (mLock) {
+            records = mContentCaptureManagerServiceStub.mCallbacks.get(packageName);
+            if (records != null) {
+                int N = records.size();
+                for (int i = 0; i < N; i++) {
+                    records.valueAt(i).setContentCaptureOptions(options);
+                }
+            }
+        }
+    }
+
     private ActivityManagerInternal getAmInternal() {
         synchronized (mLock) {
             if (mAm == null) {
@@ -599,13 +616,16 @@
     }
 
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
+        @GuardedBy("mLock")
+        private final ArrayMap<String, ArraySet<CallbackRecord>> mCallbacks = new ArrayMap<>();
 
         @Override
         public void startSession(@NonNull IBinder activityToken,
-                @NonNull ComponentName componentName, int sessionId, int flags,
-                @NonNull IResultReceiver result) {
-            Preconditions.checkNotNull(activityToken);
-            Preconditions.checkNotNull(sessionId);
+                @NonNull IBinder shareableActivityToken, @NonNull ComponentName componentName,
+                int sessionId, int flags, @NonNull IResultReceiver result) {
+            Objects.requireNonNull(activityToken);
+            Objects.requireNonNull(shareableActivityToken);
+            Objects.requireNonNull(sessionId);
             final int userId = UserHandle.getCallingUserId();
 
             final ActivityPresentationInfo activityPresentationInfo = getAmInternal()
@@ -617,14 +637,14 @@
                     setClientState(result, STATE_DISABLED, /* binder= */ null);
                     return;
                 }
-                service.startSessionLocked(activityToken, activityPresentationInfo, sessionId,
-                        Binder.getCallingUid(), flags, result);
+                service.startSessionLocked(activityToken, shareableActivityToken,
+                        activityPresentationInfo, sessionId, Binder.getCallingUid(), flags, result);
             }
         }
 
         @Override
         public void finishSession(int sessionId) {
-            Preconditions.checkNotNull(sessionId);
+            Objects.requireNonNull(sessionId);
             final int userId = UserHandle.getCallingUserId();
 
             synchronized (mLock) {
@@ -650,7 +670,7 @@
 
         @Override
         public void removeData(@NonNull DataRemovalRequest request) {
-            Preconditions.checkNotNull(request);
+            Objects.requireNonNull(request);
             assertCalledByPackageOwner(request.getPackageName());
 
             final int userId = UserHandle.getCallingUserId();
@@ -663,8 +683,8 @@
         @Override
         public void shareData(@NonNull DataShareRequest request,
                 @NonNull IDataShareWriteAdapter clientAdapter) {
-            Preconditions.checkNotNull(request);
-            Preconditions.checkNotNull(clientAdapter);
+            Objects.requireNonNull(request);
+            Objects.requireNonNull(clientAdapter);
 
             assertCalledByPackageOwner(request.getPackageName());
 
@@ -754,6 +774,46 @@
         }
 
         @Override
+        public void registerContentCaptureOptionsCallback(@NonNull String packageName,
+                IContentCaptureOptionsCallback callback) {
+            assertCalledByPackageOwner(packageName);
+
+            CallbackRecord record = new CallbackRecord(callback, packageName);
+            record.registerObserver();
+
+            synchronized (mLock) {
+                ArraySet<CallbackRecord> records = mCallbacks.get(packageName);
+                if (records == null) {
+                    records = new ArraySet<>();
+                }
+                records.add(record);
+                mCallbacks.put(packageName, records);
+            }
+
+            // Set options here in case it was updated before this was registered.
+            final int userId = UserHandle.getCallingUserId();
+            final ContentCaptureOptions options = mGlobalContentCaptureOptions.getOptions(userId,
+                    packageName);
+            if (options != null) {
+                record.setContentCaptureOptions(options);
+            }
+        }
+
+        private void unregisterContentCaptureOptionsCallback(CallbackRecord record) {
+            synchronized (mLock) {
+                ArraySet<CallbackRecord> records = mCallbacks.get(record.mPackageName);
+                if (records != null) {
+                    records.remove(record);
+                }
+
+                if (records == null || records.isEmpty()) {
+                    mCallbacks.remove(record.mPackageName);
+                }
+            }
+            record.unregisterObserver();
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
@@ -795,6 +855,23 @@
             new ContentCaptureManagerServiceShellCommand(ContentCaptureManagerService.this).exec(
                     this, in, out, err, args, callback, resultReceiver);
         }
+
+        @Override
+        public void resetTemporaryService(@UserIdInt int userId) {
+            ContentCaptureManagerService.this.resetTemporaryService(userId);
+        }
+
+        @Override
+        public void setTemporaryService(
+                @UserIdInt int userId, @NonNull String serviceName, int duration) {
+            ContentCaptureManagerService.this.setTemporaryService(
+                    userId, serviceName, duration);
+        }
+
+        @Override
+        public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+            ContentCaptureManagerService.this.setDefaultServiceEnabled(userId, enabled);
+        }
     }
 
     private final class LocalService extends ContentCaptureManagerInternal {
@@ -1200,4 +1277,39 @@
                     mDataShareRequest.getPackageName());
         }
     }
+
+    private final class CallbackRecord implements IBinder.DeathRecipient {
+        private final String mPackageName;
+        private final IContentCaptureOptionsCallback mCallback;
+
+        private CallbackRecord(IContentCaptureOptionsCallback callback, String packageName) {
+            mCallback = callback;
+            mPackageName = packageName;
+        }
+
+        private void setContentCaptureOptions(ContentCaptureOptions options) {
+            try {
+                mCallback.setContentCaptureOptions(options);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Unable to send setContentCaptureOptions(): " + e);
+            }
+        }
+
+        private void registerObserver() {
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to register callback cleanup " + e);
+            }
+        }
+
+        private void unregisterObserver() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            mContentCaptureManagerServiceStub.unregisterContentCaptureOptionsCallback(this);
+        }
+    }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index ea68e19..225a8d4 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -35,6 +35,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
+import android.app.assist.ActivityId;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
@@ -241,6 +242,7 @@
 
     @GuardedBy("mLock")
     public void startSessionLocked(@NonNull IBinder activityToken,
+            @NonNull IBinder shareableActivityToken,
             @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
             int flags, @NonNull IResultReceiver clientReceiver) {
         if (activityPresentationInfo == null) {
@@ -340,8 +342,8 @@
         mRemoteService.ensureBoundLocked();
 
         final ContentCaptureServerSession newSession = new ContentCaptureServerSession(mLock,
-                activityToken, this, componentName, clientReceiver, taskId, displayId, sessionId,
-                uid, flags);
+                activityToken, new ActivityId(taskId, shareableActivityToken), this, componentName,
+                clientReceiver, taskId, displayId, sessionId, uid, flags);
         if (mMaster.verbose) {
             Slog.v(TAG, "startSession(): new session for "
                     + ComponentName.flattenToShortString(componentName) + " and id " + sessionId);
@@ -595,9 +597,15 @@
                         ? "null_activities" : activities.size() + " activities") + ")"
                         + " for user " + mUserId);
             }
+
+            ArraySet<String> oldList =
+                    mMaster.mGlobalContentCaptureOptions.getWhitelistedPackages(mUserId);
+
             mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
             writeSetWhitelistEvent(getServiceComponentName(), packages, activities);
 
+            updateContentCaptureOptions(oldList);
+
             // Must disable session that are not the allowlist anymore...
             final int numSessions = mSessions.size();
             if (numSessions <= 0) return;
@@ -669,5 +677,23 @@
             ContentCaptureMetricsLogger.writeSessionFlush(sessionId, getServiceComponentName(), app,
                     flushMetrics, options, flushReason);
         }
+
+        /** Updates {@link ContentCaptureOptions} for all newly added packages on allowlist. */
+        private void updateContentCaptureOptions(@Nullable ArraySet<String> oldList) {
+            ArraySet<String> adding = mMaster.mGlobalContentCaptureOptions
+                    .getWhitelistedPackages(mUserId);
+
+            if (oldList != null && adding != null) {
+                adding.removeAll(oldList);
+            }
+
+            int N = adding != null ? adding.size() : 0;
+            for (int i = 0; i < N; i++) {
+                String packageName = adding.valueAt(i);
+                ContentCaptureOptions options = mMaster.mGlobalContentCaptureOptions
+                        .getOptions(mUserId, packageName);
+                mMaster.updateOptions(packageName, options);
+            }
+        }
     }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 06ab426..9f3045e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -25,6 +25,7 @@
 import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_UPDATING;
 
 import android.annotation.NonNull;
+import android.app.assist.ActivityId;
 import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -75,9 +76,9 @@
     public final ComponentName appComponentName;
 
     ContentCaptureServerSession(@NonNull Object lock, @NonNull IBinder activityToken,
-            @NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
-            @NonNull IResultReceiver sessionStateReceiver, int taskId, int displayId, int sessionId,
-            int uid, int flags) {
+            @NonNull ActivityId activityId, @NonNull ContentCapturePerUserService service,
+            @NonNull ComponentName appComponentName, @NonNull IResultReceiver sessionStateReceiver,
+            int taskId, int displayId, int sessionId, int uid, int flags) {
         Preconditions.checkArgument(sessionId != NO_SESSION_ID);
         mLock = lock;
         mActivityToken = activityToken;
@@ -86,7 +87,7 @@
         mId = sessionId;
         mUid = uid;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
-                appComponentName, taskId, displayId, flags);
+                activityId, appComponentName, displayId, flags);
         mSessionStateReceiver = sessionStateReceiver;
         try {
             sessionStateReceiver.asBinder().linkToDeath(() -> onClientDeath(), 0);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b67bdc2..8ccfad6 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -97,6 +97,7 @@
         ":platform-compat-config",
         ":platform-compat-overrides",
         ":display-device-config",
+        ":display-layout-config",
         ":cec-config",
         ":device-state-config",
         "java/com/android/server/EventLogTags.logtags",
@@ -222,7 +223,6 @@
         "java/com/android/server/TestNetworkService.java",
         "java/com/android/server/connectivity/AutodestructReference.java",
         "java/com/android/server/connectivity/ConnectivityConstants.java",
-        "java/com/android/server/connectivity/DataConnectionStats.java",
         "java/com/android/server/connectivity/DnsManager.java",
         "java/com/android/server/connectivity/KeepaliveTracker.java",
         "java/com/android/server/connectivity/LingerMonitor.java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 542d527..256e963 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -70,6 +70,7 @@
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -95,7 +96,6 @@
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
-import android.net.INetworkStatsService;
 import android.net.IOnSetOemNetworkPreferenceListener;
 import android.net.IQosCallback;
 import android.net.ISocketKeepaliveCallback;
@@ -120,6 +120,7 @@
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
@@ -141,10 +142,13 @@
 import android.net.Uri;
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
-import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
+import android.net.resolv.aidl.DnsHealthEventParcel;
+import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener;
+import android.net.resolv.aidl.Nat64PrefixEventParcel;
+import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
@@ -155,7 +159,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -187,7 +190,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.logging.MetricsLogger;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.BitUtils;
 import com.android.internal.util.IndentingPrintWriter;
@@ -201,7 +203,6 @@
 import com.android.net.module.util.PermissionUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.AutodestructReference;
-import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
 import com.android.server.connectivity.KeepaliveTracker;
@@ -324,12 +325,11 @@
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
-    private INetworkManagementService mNMS;
     @VisibleForTesting
     protected IDnsResolver mDnsResolver;
     @VisibleForTesting
     protected INetd mNetd;
-    private INetworkStatsService mStatsService;
+    private NetworkStatsManager mStatsManager;
     private NetworkPolicyManager mPolicyManager;
     private NetworkPolicyManagerInternal mPolicyManagerInternal;
     private final NetdCallback mNetdCallback;
@@ -1040,16 +1040,14 @@
         }
     }
 
-    public ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService) {
-        this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(),
+    public ConnectivityService(Context context) {
+        this(context, getDnsResolver(context), new IpConnectivityLog(),
                 NetdService.getInstance(), new Dependencies());
     }
 
     @VisibleForTesting
-    protected ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger,
-            INetd netd, Dependencies deps) {
+    protected ConnectivityService(Context context, IDnsResolver dnsresolver,
+            IpConnectivityLog logger, INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
         mDeps = Objects.requireNonNull(deps, "missing Dependencies");
@@ -1095,8 +1093,7 @@
         // TODO: Consider making the timer customizable.
         mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
 
-        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
-        mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
+        mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
         mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
         mPolicyManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
@@ -1203,7 +1200,7 @@
         mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
                 null /* broadcastPermission */, mHandler);
 
-        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
+        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
 
         mNetdCallback = new NetdCallback();
         try {
@@ -1215,9 +1212,6 @@
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
 
-        final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler);
-        dataConnectionStats.startMonitoring();
-
         mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
         mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
         mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
@@ -1237,12 +1231,12 @@
         mDnsManager = new DnsManager(mContext, mDnsResolver);
         registerPrivateDnsSettingsCallbacks();
 
-        mNoServiceNetwork =  new NetworkAgentInfo(null,
+        mNoServiceNetwork = new NetworkAgentInfo(null,
                 new Network(NO_SERVICE_NET_ID),
                 new NetworkInfo(TYPE_NONE, 0, "", ""),
                 new LinkProperties(), new NetworkCapabilities(), 0, mContext,
                 null, new NetworkAgentConfig(), this, null,
-                null, null, 0, INVALID_UID,
+                null, 0, INVALID_UID,
                 mQosCallbackTracker);
     }
 
@@ -1403,7 +1397,7 @@
         return null;
     }
 
-    private NetworkState getUnfilteredActiveNetworkState(int uid) {
+    private NetworkAgentInfo getNetworkAgentInfoForUid(int uid) {
         NetworkAgentInfo nai = getDefaultNetworkForUid(uid);
 
         final Network[] networks = getVpnUnderlyingNetworks(uid);
@@ -1419,12 +1413,7 @@
                 nai = null;
             }
         }
-
-        if (nai != null) {
-            return nai.getNetworkState();
-        } else {
-            return NetworkState.EMPTY;
-        }
+        return nai;
     }
 
     /**
@@ -1477,24 +1466,31 @@
                 "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
     }
 
-    private void filterNetworkInfo(@NonNull NetworkInfo networkInfo,
-            @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
-        if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
-            networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
-        }
-        networkInfo.setDetailedState(
-                getLegacyLockdownState(networkInfo.getDetailedState()),
-                "" /* reason */, null /* extraInfo */);
-    }
-
     /**
-     * Apply any relevant filters to {@link NetworkState} for the given UID. For
+     * Apply any relevant filters to the specified {@link NetworkInfo} for the given UID. For
      * example, this may mark the network as {@link DetailedState#BLOCKED} based
      * on {@link #isNetworkWithCapabilitiesBlocked}.
      */
-    private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
-        if (state == null || state.networkInfo == null || state.linkProperties == null) return;
-        filterNetworkInfo(state.networkInfo, state.networkCapabilities, uid, ignoreBlocked);
+    @NonNull
+    private NetworkInfo filterNetworkInfo(@NonNull NetworkInfo networkInfo, int type,
+            @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
+        final NetworkInfo filtered = new NetworkInfo(networkInfo);
+        // Many legacy types (e.g,. TYPE_MOBILE_HIPRI) are not actually a property of the network
+        // but only exists if an app asks about them or requests them. Ensure the requesting app
+        // gets the type it asks for.
+        filtered.setType(type);
+        final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)
+                ? DetailedState.BLOCKED
+                : filtered.getDetailedState();
+        filtered.setDetailedState(getLegacyLockdownState(state),
+                "" /* reason */, null /* extraInfo */);
+        return filtered;
+    }
+
+    private NetworkInfo getFilteredNetworkInfo(NetworkAgentInfo nai, int uid,
+            boolean ignoreBlocked) {
+        return filterNetworkInfo(nai.networkInfo, nai.networkInfo.getType(),
+                nai.networkCapabilities, uid, ignoreBlocked);
     }
 
     /**
@@ -1508,10 +1504,11 @@
     public NetworkInfo getActiveNetworkInfo() {
         enforceAccessPermission();
         final int uid = mDeps.getCallingUid();
-        final NetworkState state = getUnfilteredActiveNetworkState(uid);
-        filterNetworkStateForUid(state, uid, false);
-        maybeLogBlockedNetworkInfo(state.networkInfo, uid);
-        return state.networkInfo;
+        final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+        if (nai == null) return null;
+        final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
+        maybeLogBlockedNetworkInfo(networkInfo, uid);
+        return networkInfo;
     }
 
     @Override
@@ -1546,30 +1543,37 @@
     @Override
     public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
-        final NetworkState state = getUnfilteredActiveNetworkState(uid);
-        filterNetworkStateForUid(state, uid, ignoreBlocked);
-        return state.networkInfo;
+        final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+        if (nai == null) return null;
+        return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
     }
 
-    private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
+    /** Returns a NetworkInfo object for a network that doesn't exist. */
+    private NetworkInfo makeFakeNetworkInfo(int networkType, int uid) {
+        final NetworkInfo info = new NetworkInfo(networkType, 0 /* subtype */,
+                getNetworkTypeName(networkType), "" /* subtypeName */);
+        info.setIsAvailable(true);
+        // For compatibility with legacy code, return BLOCKED instead of DISCONNECTED when
+        // background data is restricted.
+        final NetworkCapabilities nc = new NetworkCapabilities();  // Metered.
+        final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false)
+                ? DetailedState.BLOCKED
+                : DetailedState.DISCONNECTED;
+        info.setDetailedState(getLegacyLockdownState(state),
+                "" /* reason */, null /* extraInfo */);
+        return info;
+    }
+
+    private NetworkInfo getFilteredNetworkInfoForType(int networkType, int uid) {
         if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
             return null;
         }
         final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
-        final NetworkInfo info;
-        final NetworkCapabilities nc;
-        if (nai != null) {
-            info = new NetworkInfo(nai.networkInfo);
-            info.setType(networkType);
-            nc = nai.networkCapabilities;
-        } else {
-            info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), "");
-            info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
-            info.setIsAvailable(true);
-            nc = new NetworkCapabilities();
+        if (nai == null) {
+            return makeFakeNetworkInfo(networkType, uid);
         }
-        filterNetworkInfo(info, nc, uid, false);
-        return info;
+        return filterNetworkInfo(nai.networkInfo, networkType, nai.networkCapabilities, uid,
+                false);
     }
 
     @Override
@@ -1579,27 +1583,23 @@
         if (getVpnUnderlyingNetworks(uid) != null) {
             // A VPN is active, so we may need to return one of its underlying networks. This
             // information is not available in LegacyTypeTracker, so we have to get it from
-            // getUnfilteredActiveNetworkState.
-            final NetworkState state = getUnfilteredActiveNetworkState(uid);
-            if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
-                filterNetworkStateForUid(state, uid, false);
-                return state.networkInfo;
+            // getNetworkAgentInfoForUid.
+            final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+            if (nai == null) return null;
+            final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
+            if (networkInfo.getType() == networkType) {
+                return networkInfo;
             }
         }
-        return getFilteredNetworkInfo(networkType, uid);
+        return getFilteredNetworkInfoForType(networkType, uid);
     }
 
     @Override
     public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
         enforceAccessPermission();
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-        if (nai != null) {
-            final NetworkState state = nai.getNetworkState();
-            filterNetworkStateForUid(state, uid, ignoreBlocked);
-            return state.networkInfo;
-        } else {
-            return null;
-        }
+        if (nai == null) return null;
+        return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
     }
 
     @Override
@@ -1627,10 +1627,10 @@
             return null;
         }
         final int uid = mDeps.getCallingUid();
-        if (!isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
-            return nai.network;
+        if (isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
+            return null;
         }
-        return null;
+        return nai.network;
     }
 
     @Override
@@ -1719,9 +1719,9 @@
     public LinkProperties getActiveLinkProperties() {
         enforceAccessPermission();
         final int uid = mDeps.getCallingUid();
-        NetworkState state = getUnfilteredActiveNetworkState(uid);
-        if (state.linkProperties == null) return null;
-        return linkPropertiesRestrictedForCallerPermissions(state.linkProperties,
+        NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+        if (nai == null) return null;
+        return linkPropertiesRestrictedForCallerPermissions(nai.linkProperties,
                 Binder.getCallingPid(), uid);
     }
 
@@ -2040,25 +2040,24 @@
         return true;
     }
 
-    private class NetdEventCallback extends INetdEventListener.Stub {
+    class DnsResolverUnsolicitedEventCallback extends
+            IDnsResolverUnsolicitedEventListener.Stub {
         @Override
-        public void onPrivateDnsValidationEvent(int netId, String ipAddress,
-                String hostname, boolean validated) {
+        public void onPrivateDnsValidationEvent(final PrivateDnsValidationEventParcel event) {
             try {
                 mHandler.sendMessage(mHandler.obtainMessage(
                         EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
-                        new PrivateDnsValidationUpdate(netId,
-                                InetAddresses.parseNumericAddress(ipAddress),
-                                hostname, validated)));
+                        new PrivateDnsValidationUpdate(event.netId,
+                                InetAddresses.parseNumericAddress(event.ipAddress),
+                                event.hostname, event.validation)));
             } catch (IllegalArgumentException e) {
                 loge("Error parsing ip address in validation event");
             }
         }
 
         @Override
-        public void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
-                String hostname,  String[] ipAddresses, int ipAddressesCount, int uid) {
-            NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
+        public void onDnsHealthEvent(final DnsHealthEventParcel event) {
+            NetworkAgentInfo nai = getNetworkAgentInfoForNetId(event.netId);
             // Netd event only allow registrants from system. Each NetworkMonitor thread is under
             // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
             // event callback for certain nai. e.g. cellular. Register here to pass to
@@ -2067,34 +2066,18 @@
             // callback from each caller type. Need to re-factor NetdEventListenerService to allow
             // multiple NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) {
-                nai.networkMonitor().notifyDnsResponse(returnCode);
+                nai.networkMonitor().notifyDnsResponse(event.healthResult);
             }
         }
 
         @Override
-        public void onNat64PrefixEvent(int netId, boolean added,
-                                       String prefixString, int prefixLength) {
-            mHandler.post(() -> handleNat64PrefixEvent(netId, added, prefixString, prefixLength));
+        public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) {
+            mHandler.post(() -> handleNat64PrefixEvent(event.netId, event.prefixOperation,
+                    event.prefixAddress, event.prefixLength));
         }
 
         @Override
-        public void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port,
-                int uid) {
-        }
-
-        @Override
-        public void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
-                byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort,
-                long timestampNs) {
-        }
-
-        @Override
-        public void onTcpSocketStatsEvent(int[] networkIds, int[] sentPackets, int[] lostPackets,
-                int[] rttsUs, int[] sentAckDiffsMs) {
-        }
-
-        @Override
-        public int getInterfaceVersion() throws RemoteException {
+        public int getInterfaceVersion() {
             return this.VERSION;
         }
 
@@ -2102,16 +2085,17 @@
         public String getInterfaceHash() {
             return this.HASH;
         }
-    };
+    }
 
     @VisibleForTesting
-    protected final INetdEventListener mNetdEventCallback = new NetdEventCallback();
+    protected final DnsResolverUnsolicitedEventCallback mResolverUnsolEventCallback =
+            new DnsResolverUnsolicitedEventCallback();
 
-    private void registerNetdEventCallback() {
+    private void registerDnsResolverUnsolicitedEventListener() {
         try {
-            mDnsResolver.registerEventListener(mNetdEventCallback);
+            mDnsResolver.registerUnsolicitedEventListener(mResolverUnsolEventCallback);
         } catch (Exception e) {
-            loge("Error registering DnsResolver callback: " + e);
+            loge("Error registering DnsResolver unsolicited event callback: " + e);
         }
     }
 
@@ -2201,8 +2185,45 @@
                 "ConnectivityService");
     }
 
+    /**
+     * Performs a strict and comprehensive check of whether a calling package is allowed to
+     * change the state of network, as the condition differs for pre-M, M+, and
+     * privileged/preinstalled apps. The caller is expected to have either the
+     * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
+     * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
+     * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
+     * permission and cannot be revoked. See http://b/23597341
+     *
+     * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
+     * of this app will be updated to the current time.
+     */
     private void enforceChangePermission(String callingPkg, String callingAttributionTag) {
-        ConnectivityManager.enforceChangePermission(mContext, callingPkg, callingAttributionTag);
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
+                == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (callingPkg == null) {
+            throw new SecurityException("Calling package name is null.");
+        }
+
+        final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class);
+        final int uid = mDeps.getCallingUid();
+        final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid,
+                callingPkg, callingAttributionTag, null /* message */);
+
+        if (mode == AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
+        if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) {
+            return;
+        }
+
+        throw new SecurityException(callingPkg + " was not granted either of these permissions:"
+                + android.Manifest.permission.CHANGE_NETWORK_STATE + ","
+                + android.Manifest.permission.WRITE_SETTINGS + ".");
     }
 
     private void enforceSettingsPermission() {
@@ -2363,13 +2384,6 @@
                 final BroadcastOptions opts = BroadcastOptions.makeBasic();
                 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
                 options = opts.toBundle();
-                final IBatteryStats bs = mDeps.getBatteryStatsService();
-                try {
-                    bs.noteConnectivityChanged(intent.getIntExtra(
-                            ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
-                            ni.getState().toString());
-                } catch (RemoteException e) {
-                }
                 intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
             }
             try {
@@ -2405,7 +2419,7 @@
         // to ensure the tracking will be initialized correctly.
         mPermissionMonitor.startMonitoring();
         mProxyTracker.loadGlobalProxy();
-        registerNetdEventCallback();
+        registerDnsResolverUnsolicitedEventListener();
 
         synchronized (this) {
             mSystemReady = true;
@@ -3046,9 +3060,6 @@
                 log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
             }
             if (valid != nai.lastValidated) {
-                if (wasDefault) {
-                    mMetricsLog.logDefaultNetworkValidity(valid);
-                }
                 final int oldScore = nai.getCurrentScore();
                 nai.lastValidated = valid;
                 nai.everValidated |= valid;
@@ -3172,16 +3183,16 @@
             // Invoke ConnectivityReport generation for this Network test event.
             final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(mNetId);
             if (nai == null) return;
-            final Message m = mConnectivityDiagnosticsHandler.obtainMessage(
-                    ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED,
-                    new ConnectivityReportEvent(p.timestampMillis, nai));
 
             final PersistableBundle extras = new PersistableBundle();
             extras.putInt(KEY_NETWORK_VALIDATION_RESULT, p.result);
             extras.putInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, p.probesSucceeded);
             extras.putInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK, p.probesAttempted);
 
-            m.setData(new Bundle(extras));
+            ConnectivityReportEvent reportEvent =
+                    new ConnectivityReportEvent(p.timestampMillis, nai, extras);
+            final Message m = mConnectivityDiagnosticsHandler.obtainMessage(
+                    ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED, reportEvent);
             mConnectivityDiagnosticsHandler.sendMessage(m);
         }
 
@@ -3268,8 +3279,7 @@
 
         final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
                 ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, detectionMethod, netId,
-                p.timestampMillis);
-        msg.setData(new Bundle(extras));
+                new Pair<>(p.timestampMillis, extras));
 
         // NetworkStateTrackerHandler currently doesn't take any actions based on data
         // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
@@ -3336,21 +3346,21 @@
         handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
     }
 
-    private void handleNat64PrefixEvent(int netId, boolean added, String prefixString,
+    private void handleNat64PrefixEvent(int netId, int operation, String prefixAddress,
             int prefixLength) {
         NetworkAgentInfo nai = mNetworkForNetId.get(netId);
         if (nai == null) return;
 
-        log(String.format("NAT64 prefix %s on netId %d: %s/%d",
-                          (added ? "added" : "removed"), netId, prefixString, prefixLength));
+        log(String.format("NAT64 prefix changed on netId %d: operation=%d, %s/%d",
+                netId, operation, prefixAddress, prefixLength));
 
         IpPrefix prefix = null;
-        if (added) {
+        if (operation == IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED) {
             try {
-                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixString),
+                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixAddress),
                         prefixLength);
             } catch (IllegalArgumentException e) {
-                loge("Invalid NAT64 prefix " + prefixString + "/" + prefixLength);
+                loge("Invalid NAT64 prefix " + prefixAddress + "/" + prefixLength);
                 return;
             }
         }
@@ -3469,14 +3479,6 @@
         final boolean wasDefault = isDefaultNetwork(nai);
         if (wasDefault) {
             mDefaultInetConditionPublished = 0;
-            // Log default network disconnection before required book-keeping.
-            // Let rematchAllNetworksAndRequests() below record a new default network event
-            // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
-            // whose timestamps tell how long it takes to recover a default network.
-            long now = SystemClock.elapsedRealtime();
-            mMetricsLog.logDefaultNetworkEvent(null, 0, false,
-                    null /* lp */, null /* nc */, nai.network, nai.getCurrentScore(),
-                    nai.linkProperties, nai.networkCapabilities);
         }
         notifyIfacesChangedForNetworkStats();
         // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -3818,7 +3820,24 @@
                 removeListenRequestFromNetworks(req);
             }
         }
-        mDefaultNetworkRequests.remove(nri);
+        if (mDefaultNetworkRequests.remove(nri)) {
+            // If this request was one of the defaults, then the UID rules need to be updated
+            // WARNING : if the app(s) for which this network request is the default are doing
+            // traffic, this will kill their connected sockets, even if an equivalent request
+            // is going to be reinstated right away ; unconnected traffic will go on the default
+            // until the new default is set, which will happen very soon.
+            // TODO : The only way out of this is to diff old defaults and new defaults, and only
+            // remove ranges for those requests that won't have a replacement
+            final NetworkAgentInfo satisfier = nri.getSatisfier();
+            if (null != satisfier) {
+                try {
+                    mNetd.networkRemoveUidRanges(satisfier.network.getNetId(),
+                            toUidRangeStableParcels(nri.getUids()));
+                } catch (RemoteException e) {
+                    loge("Exception setting network preference default network", e);
+                }
+            }
+        }
         mNetworkRequestCounter.decrementCount(nri.mUid);
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
 
@@ -4131,13 +4150,6 @@
             // nai.networkMonitor() is thread-safe
             return nai.networkMonitor();
         }
-
-        @Override
-        public void logEvent(int eventId, String packageName) {
-            enforceSettingsPermission();
-
-            new MetricsLogger().action(eventId, packageName);
-        }
     }
 
     public boolean avoidBadWifi() {
@@ -4467,16 +4479,13 @@
                 case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
                     handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
                     break;
-                case EVENT_SET_OEM_NETWORK_PREFERENCE:
+                case EVENT_SET_OEM_NETWORK_PREFERENCE: {
                     final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
                             (Pair<OemNetworkPreferences,
                                     IOnSetOemNetworkPreferenceListener>) msg.obj;
-                    try {
-                        handleSetOemNetworkPreference(arg.first, arg.second);
-                    } catch (RemoteException e) {
-                        loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
-                    }
+                    handleSetOemNetworkPreference(arg.first, arg.second);
                     break;
+                }
                 case EVENT_REPORT_NETWORK_ACTIVITY:
                     mNetworkActivityTracker.handleReportNetworkActivity();
                     break;
@@ -5234,11 +5243,20 @@
             ensureAllNetworkRequestsHaveType(r);
             mRequests = initializeRequests(r);
             mNetworkRequestForCallback = nri.getNetworkRequestForCallback();
+            // Note here that the satisfier may have corresponded to an old request, that
+            // this code doesn't try to take over. While it is a small discrepancy in the
+            // structure of these requests, it will be fixed by the next rematch and it's
+            // not as bad as having an NRI not storing its real satisfier.
+            // Fixing this discrepancy would require figuring out in the copying code what
+            // is the new request satisfied by this, which is a bit complex and not very
+            // useful as no code is using it until rematch fixes it.
+            mSatisfier = nri.mSatisfier;
             mMessenger = nri.mMessenger;
             mBinder = nri.mBinder;
             mPid = nri.mPid;
             mUid = nri.mUid;
             mPendingIntent = nri.mPendingIntent;
+            mNetworkRequestCounter.incrementCountOrThrow(mUid);
             mCallingAttributionTag = nri.mCallingAttributionTag;
         }
 
@@ -5285,6 +5303,8 @@
         public String toString() {
             return "uid/pid:" + mUid + "/" + mPid + " active request Id: "
                     + (mActiveRequest == null ? null : mActiveRequest.requestId)
+                    + " callback request Id: "
+                    + mNetworkRequestForCallback.requestId
                     + " " + mRequests
                     + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
         }
@@ -6030,7 +6050,7 @@
         final NetworkAgentInfo nai = new NetworkAgentInfo(na,
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
                 currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
-                this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
+                this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker);
 
         // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
         processCapabilitiesFromAgent(nai, nc);
@@ -7112,27 +7132,6 @@
         updateTcpBufferSizes(null != newDefaultNetwork
                 ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null);
         notifyIfacesChangedForNetworkStats();
-
-        // Log 0 -> X and Y -> X default network transitions, where X is the new default.
-        final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
-        final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
-        final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
-        final LinkProperties lp = (newDefaultNetwork != null)
-                ? newDefaultNetwork.linkProperties : null;
-        final NetworkCapabilities nc = (newDefaultNetwork != null)
-                ? newDefaultNetwork.networkCapabilities : null;
-
-        final Network prevNetwork = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.network : null;
-        final int prevScore = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.getCurrentScore() : 0;
-        final LinkProperties prevLp = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.linkProperties : null;
-        final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.networkCapabilities : null;
-
-        mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
-                prevNetwork, prevScore, prevLp, prevNc);
     }
 
     private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri,
@@ -7162,7 +7161,7 @@
                         toUidRangeStableParcels(nri.getUids()));
             }
         } catch (RemoteException | ServiceSpecificException e) {
-            loge("Exception setting OEM network preference default network :" + e);
+            loge("Exception setting OEM network preference default network", e);
         }
     }
 
@@ -7217,13 +7216,13 @@
     private static class NetworkReassignment {
         static class RequestReassignment {
             @NonNull public final NetworkRequestInfo mNetworkRequestInfo;
-            @NonNull public final NetworkRequest mOldNetworkRequest;
-            @NonNull public final NetworkRequest mNewNetworkRequest;
+            @Nullable public final NetworkRequest mOldNetworkRequest;
+            @Nullable public final NetworkRequest mNewNetworkRequest;
             @Nullable public final NetworkAgentInfo mOldNetwork;
             @Nullable public final NetworkAgentInfo mNewNetwork;
             RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo,
-                    @NonNull final NetworkRequest oldNetworkRequest,
-                    @NonNull final NetworkRequest newNetworkRequest,
+                    @Nullable final NetworkRequest oldNetworkRequest,
+                    @Nullable final NetworkRequest newNetworkRequest,
                     @Nullable final NetworkAgentInfo oldNetwork,
                     @Nullable final NetworkAgentInfo newNetwork) {
                 mNetworkRequestInfo = networkRequestInfo;
@@ -7234,7 +7233,9 @@
             }
 
             public String toString() {
-                return mNetworkRequestInfo.mRequests.get(0).requestId + " : "
+                final NetworkRequest requestToShow = null != mNewNetworkRequest
+                        ? mNewNetworkRequest : mNetworkRequestInfo.mRequests.get(0);
+                return requestToShow.requestId + " : "
                         + (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
                         + " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
             }
@@ -7294,14 +7295,14 @@
     }
 
     private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
-            @NonNull final NetworkRequest previousRequest,
-            @NonNull final NetworkRequest newRequest,
+            @Nullable final NetworkRequest previousRequest,
+            @Nullable final NetworkRequest newRequest,
             @Nullable final NetworkAgentInfo previousSatisfier,
             @Nullable final NetworkAgentInfo newSatisfier,
             final long now) {
         if (null != newSatisfier && mNoServiceNetwork != newSatisfier) {
             if (VDBG) log("rematch for " + newSatisfier.toShortString());
-            if (null != previousSatisfier && mNoServiceNetwork != previousSatisfier) {
+            if (null != previousRequest && null != previousSatisfier) {
                 if (VDBG || DDBG) {
                     log("   accepting network in place of " + previousSatisfier.toShortString());
                 }
@@ -7318,12 +7319,13 @@
                 newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE);
             }
 
+            // if newSatisfier is not null, then newRequest may not be null.
             newSatisfier.unlingerRequest(newRequest.requestId);
             if (!newSatisfier.addRequest(newRequest)) {
                 Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
                         + newRequest);
             }
-        } else if (null != previousSatisfier) {
+        } else if (null != previousRequest && null != previousSatisfier) {
             if (DBG) {
                 log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
                         + " request " + previousRequest.requestId);
@@ -7921,7 +7923,8 @@
      *
      * Must be called on the handler thread.
      */
-    private Network[] getDefaultNetworks() {
+    @NonNull
+    private ArrayList<Network> getDefaultNetworks() {
         ensureRunningOnConnectivityServiceThread();
         final ArrayList<Network> defaultNetworks = new ArrayList<>();
         final Set<Integer> activeNetIds = new ArraySet<>();
@@ -7935,7 +7938,7 @@
                 defaultNetworks.add(nai.network);
             }
         }
-        return defaultNetworks.toArray(new Network[0]);
+        return defaultNetworks;
     }
 
     /**
@@ -7952,8 +7955,16 @@
 
         final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
         try {
-            mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
-                    underlyingNetworkInfos);
+            final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>();
+            // TODO: Directly use NetworkStateSnapshot when feasible.
+            for (final NetworkState state : getAllNetworkState()) {
+                final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
+                        state.networkCapabilities, state.linkProperties, state.subscriberId,
+                        state.legacyNetworkType);
+                snapshots.add(snapshot);
+            }
+            mStatsManager.notifyNetworkStatus(getDefaultNetworks(),
+                    snapshots, activeIface, Arrays.asList(underlyingNetworkInfos));
         } catch (Exception ignored) {
         }
     }
@@ -8186,7 +8197,7 @@
             TestNetworkService.enforceTestNetworkPermissions(mContext);
 
             if (mTNS == null) {
-                mTNS = new TestNetworkService(mContext, mNMS);
+                mTNS = new TestNetworkService(mContext);
             }
 
             return mTNS;
@@ -8272,24 +8283,16 @@
                     final ConnectivityReportEvent reportEvent =
                             (ConnectivityReportEvent) msg.obj;
 
-                    // This is safe because {@link
-                    // NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} receives a
-                    // PersistableBundle and converts it to the Bundle in the incoming Message. If
-                    // {@link NetworkMonitorCallbacks#notifyNetworkTested} is called, msg.data will
-                    // not be set. This is also safe, as msg.getData() will return an empty Bundle.
-                    final PersistableBundle extras = new PersistableBundle(msg.getData());
-                    handleNetworkTestedWithExtras(reportEvent, extras);
+                    handleNetworkTestedWithExtras(reportEvent, reportEvent.mExtras);
                     break;
                 }
                 case EVENT_DATA_STALL_SUSPECTED: {
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
+                    final Pair<Long, PersistableBundle> arg =
+                            (Pair<Long, PersistableBundle>) msg.obj;
                     if (nai == null) break;
 
-                    // This is safe because NetworkMonitorCallbacks#notifyDataStallSuspected
-                    // receives a PersistableBundle and converts it to the Bundle in the incoming
-                    // Message.
-                    final PersistableBundle extras = new PersistableBundle(msg.getData());
-                    handleDataStallSuspected(nai, (long) msg.obj, msg.arg1, extras);
+                    handleDataStallSuspected(nai, arg.first, msg.arg1, arg.second);
                     break;
                 }
                 case EVENT_NETWORK_CONNECTIVITY_REPORTED: {
@@ -8353,10 +8356,13 @@
     private static class ConnectivityReportEvent {
         private final long mTimestampMillis;
         @NonNull private final NetworkAgentInfo mNai;
+        private final PersistableBundle mExtras;
 
-        private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai) {
+        private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai,
+                PersistableBundle p) {
             mTimestampMillis = timestampMillis;
             mNai = nai;
+            mExtras = p;
         }
     }
 
@@ -8661,9 +8667,23 @@
 
     private class NetdCallback extends BaseNetdUnsolicitedEventListener {
         @Override
-        public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel,
+        public void onInterfaceClassActivityChanged(boolean isActive, int transportType,
                 long timestampNs, int uid) {
-            mNetworkActivityTracker.setAndReportNetworkActive(isActive, timerLabel, timestampNs);
+            mNetworkActivityTracker.setAndReportNetworkActive(isActive, transportType, timestampNs);
+        }
+
+        @Override
+        public void onInterfaceLinkStateChanged(String iface, boolean up) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
+                nai.clatd.interfaceLinkStateChanged(iface, up);
+            }
+        }
+
+        @Override
+        public void onInterfaceRemoved(String iface) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
+                nai.clatd.interfaceRemoved(iface);
+            }
         }
     }
 
@@ -8697,7 +8717,7 @@
         }
 
         LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
-                @NonNull INetworkManagementService nms, @NonNull INetd netd) {
+                @NonNull INetd netd) {
             mContext = context;
             mNetd = netd;
             mHandler = handler;
@@ -9019,7 +9039,7 @@
 
     private void handleSetOemNetworkPreference(
             @NonNull final OemNetworkPreferences preference,
-            @NonNull final IOnSetOemNetworkPreferenceListener listener) throws RemoteException {
+            @Nullable final IOnSetOemNetworkPreferenceListener listener) {
         Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
         if (DBG) {
             log("set OEM network preferences :" + preference.toString());
@@ -9031,7 +9051,11 @@
         // TODO http://b/176496396 persist data to shared preferences.
 
         if (null != listener) {
-            listener.onComplete();
+            try {
+                listener.onComplete();
+            } catch (RemoteException e) {
+                loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
+            }
         }
     }
 
@@ -9047,10 +9071,10 @@
         mDefaultNetworkRequests.addAll(nris);
         final ArraySet<NetworkRequestInfo> perAppCallbackRequestsToUpdate =
                 getPerAppCallbackRequestsToUpdate();
-        handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
         final ArraySet<NetworkRequestInfo> nrisToRegister = new ArraySet<>(nris);
         nrisToRegister.addAll(
                 createPerAppCallbackRequestsToRegister(perAppCallbackRequestsToUpdate));
+        handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
         handleRegisterNetworkRequests(nrisToRegister);
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index 0779f71..b992208 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -20,9 +20,6 @@
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
 
 import android.content.Context;
-import android.net.INetworkStatsService;
-import android.os.INetworkManagementService;
-import android.os.ServiceManager;
 import android.util.Log;
 
 /**
@@ -38,8 +35,7 @@
         // Load JNI libraries used by ConnectivityService and its dependencies
         System.loadLibrary("service-connectivity");
         // TODO: Define formal APIs to get the needed services.
-        mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
-                getNetworkStatsService());
+        mConnectivity = new ConnectivityService(context);
     }
 
     @Override
@@ -48,14 +44,4 @@
         publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
                 /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
     }
-
-    private INetworkManagementService getNetworkManagementService() {
-        return INetworkManagementService.Stub.asInterface(
-               ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-    }
-
-    private INetworkStatsService getNetworkStatsService() {
-        return INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
-    }
 }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 4405408..10d6570 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -44,7 +44,6 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.INetdUnsolicitedEventListener;
 import android.net.INetworkManagementEventObserver;
@@ -54,7 +53,6 @@
 import android.net.InterfaceConfigurationParcel;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
-import android.net.Network;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkStack;
 import android.net.NetworkStats;
@@ -974,19 +972,6 @@
     }
 
     @Override
-    public void setDnsForwarders(Network network, String[] dns) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
-
-        try {
-            mNetdService.tetherDnsSet(netId, dns);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
     public String[] getDnsForwarders() {
         NetworkStack.checkNetworkStackPermission(mContext);
         try {
@@ -1775,27 +1760,6 @@
     }
 
     @Override
-    public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        final LinkAddress la = routeInfo.getDestinationLinkAddress();
-        final String ifName = routeInfo.getInterface();
-        final String dst = la.toString();
-        final String nextHop;
-
-        if (routeInfo.hasGateway()) {
-            nextHop = routeInfo.getGateway().getHostAddress();
-        } else {
-            nextHop = "";
-        }
-        try {
-            mNetdService.networkAddLegacyRoute(netId, ifName, dst, nextHop, uid);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
     public void allowProtect(int uid) {
         NetworkStack.checkNetworkStackPermission(mContext);
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 233a50d..27b648e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -24,6 +24,10 @@
 import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
 import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -55,6 +59,7 @@
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
 import android.app.admin.SecurityLog;
 import android.app.usage.StorageStatsManager;
 import android.content.BroadcastReceiver;
@@ -573,6 +578,12 @@
      */
     private static final int PBKDF2_HASH_ROUNDS = 1024;
 
+    private static final String ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY =
+            "anr_delay_millis";
+
+    private static final String ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY =
+            "anr_delay_notify_external_storage_service";
+
     /**
      * Mounted OBB tracking information. Used to track the current state of all
      * OBBs.
@@ -943,25 +954,51 @@
         }
     }
 
-    // TODO(b/170486601): Check transcoding status based on events pushed from the MediaProvider
     private class ExternalStorageServiceAnrController implements AnrController {
         @Override
         public long getAnrDelayMillis(String packageName, int uid) {
-            int delay = SystemProperties.getInt("sys.fuse.transcode_anr_delay", 0);
-            Log.d(TAG, "getAnrDelayMillis: " + packageName + ". Delaying for " + delay + "ms");
+            if (!isAppIoBlocked(uid)) {
+                return 0;
+            }
+
+            int delay = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                    ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY, 0);
+            Slog.v(TAG, "getAnrDelayMillis for " + packageName + ". " + delay + "ms");
             return delay;
         }
 
         @Override
         public void onAnrDelayStarted(String packageName, int uid) {
-            Log.d(TAG, "onAnrDelayStarted: " + packageName);
+            if (!isAppIoBlocked(uid)) {
+                return;
+            }
+
+            boolean notifyExternalStorageService = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                    ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY, true);
+            if (notifyExternalStorageService) {
+                Slog.d(TAG, "onAnrDelayStarted for " + packageName
+                        + ". Notifying external storage service");
+                try {
+                    mStorageSessionController.notifyAnrDelayStarted(packageName, uid, 0 /* tid */,
+                            StorageManager.APP_IO_BLOCKED_REASON_TRANSCODING);
+                } catch (ExternalStorageServiceException e) {
+                    Slog.e(TAG, "Failed to notify ANR delay started for " + packageName, e);
+                }
+            } else {
+                // TODO(b/170973510): Implement framework spinning dialog for ANR delay
+            }
         }
 
         @Override
         public boolean onAnrDelayCompleted(String packageName, int uid) {
-            boolean show = SystemProperties.getBoolean("sys.fuse.transcode_anr_dialog_show", true);
-            Log.d(TAG, "onAnrDelayCompleted: " + packageName + ". Show: " + show);
-            return show;
+            if (isAppIoBlocked(uid)) {
+                Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Showing ANR dialog...");
+                return true;
+            } else {
+                Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Skipping ANR dialog...");
+                return false;
+            }
         }
     }
 
@@ -3371,6 +3408,54 @@
         }
     }
 
+    /**
+     * Returns PendingIntent which can be used by Apps with MANAGE_EXTERNAL_STORAGE permission
+     * to launch the manageSpaceActivity of the App specified by packageName.
+     */
+    @Override
+    @Nullable
+    public PendingIntent getManageSpaceActivityIntent(
+            @NonNull String packageName, int requestCode) {
+        // Only Apps with MANAGE_EXTERNAL_STORAGE permission should be able to call this API.
+        enforcePermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE);
+
+        // We want to call the manageSpaceActivity as a SystemService and clear identity
+        // of the calling App
+        int originalUid = Binder.getCallingUidOrThrow();
+        long token = Binder.clearCallingIdentity();
+
+        try {
+            ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0,
+                    UserHandle.getUserId(originalUid));
+            if (appInfo == null) {
+                throw new IllegalArgumentException(
+                        "Invalid packageName");
+            }
+            if (appInfo.manageSpaceActivityName == null) {
+                Log.i(TAG, packageName + " doesn't have a manageSpaceActivity");
+                return null;
+            }
+            Context targetAppContext = mContext.createPackageContext(packageName, 0);
+
+            Intent intent = new Intent(Intent.ACTION_DEFAULT);
+            intent.setClassName(packageName,
+                    appInfo.manageSpaceActivityName);
+            intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+
+            PendingIntent activity = PendingIntent.getActivity(targetAppContext, requestCode,
+                    intent,
+                    FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
+            return activity;
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException(
+                    "packageName not found");
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
         private boolean mMounted = false;
@@ -4637,5 +4722,19 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public List<String> getPrimaryVolumeIds() {
+            final List<String> primaryVolumeIds = new ArrayList<>();
+            synchronized (mLock) {
+                for (int i = 0; i < mVolumes.size(); i++) {
+                    final VolumeInfo vol = mVolumes.valueAt(i);
+                    if (vol.isPrimary()) {
+                        primaryVolumeIds.add(vol.getId());
+                    }
+                }
+            }
+            return primaryVolumeIds;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 96f832d..55408ea 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -32,7 +32,6 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
-import android.net.NetworkStack;
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
 import android.net.TestNetworkInterface;
@@ -41,7 +40,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -51,6 +49,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.NetworkStackConstants;
+import com.android.net.module.util.PermissionUtils;
 
 import java.io.UncheckedIOException;
 import java.net.Inet4Address;
@@ -69,7 +68,6 @@
     @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
 
     @NonNull private final Context mContext;
-    @NonNull private final INetworkManagementService mNMS;
     @NonNull private final INetd mNetd;
 
     @NonNull private final HandlerThread mHandlerThread;
@@ -82,14 +80,12 @@
     private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
 
     @VisibleForTesting
-    protected TestNetworkService(
-            @NonNull Context context, @NonNull INetworkManagementService netManager) {
+    protected TestNetworkService(@NonNull Context context) {
         mHandlerThread = new HandlerThread("TestNetworkServiceThread");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
 
         mContext = Objects.requireNonNull(context, "missing Context");
-        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
@@ -324,7 +320,7 @@
         try {
             final long token = Binder.clearCallingIdentity();
             try {
-                NetworkStack.checkNetworkStackPermission(mContext);
+                PermissionUtils.enforceNetworkStackPermission(mContext);
                 NetdUtils.setInterfaceUp(mNetd, iface);
             } finally {
                 Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 8d5d3d9..ad2f524 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -35,6 +35,7 @@
 import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnManager;
 import android.net.vcn.VcnManager.VcnErrorCode;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
 import android.net.wifi.WifiInfo;
@@ -724,6 +725,26 @@
         }
     }
 
+    private boolean isCallbackPermissioned(
+            @NonNull VcnStatusCallbackInfo cbInfo, @NonNull ParcelUuid subgroup) {
+        if (!subgroup.equals(cbInfo.mSubGroup)) {
+            return false;
+        }
+
+        if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subgroup, cbInfo.mPkgName)) {
+            return false;
+        }
+
+        if (!mLocationPermissionChecker.checkLocationPermission(
+                cbInfo.mPkgName,
+                "VcnStatusCallback" /* featureId */,
+                cbInfo.mUid,
+                null /* message */)) {
+            return false;
+        }
+        return true;
+    }
+
     /** Registers the provided callback for receiving VCN status updates. */
     @Override
     public void registerVcnStatusCallback(
@@ -758,6 +779,27 @@
                 }
 
                 mRegisteredStatusCallbacks.put(cbBinder, cbInfo);
+
+                // now that callback is registered, send it the VCN's current status
+                final VcnConfig vcnConfig = mConfigs.get(subGroup);
+                final Vcn vcn = mVcns.get(subGroup);
+                final int vcnStatus;
+                if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) {
+                    vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
+                } else if (vcn == null) {
+                    vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE;
+                } else if (vcn.isActive()) {
+                    vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE;
+                } else {
+                    // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status
+                    vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+                }
+
+                try {
+                    cbInfo.mCallback.onVcnStatusChanged(vcnStatus);
+                } catch (RemoteException e) {
+                    Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -806,26 +848,6 @@
             mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup");
         }
 
-        private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) {
-            if (!mSubGroup.equals(cbInfo.mSubGroup)) {
-                return false;
-            }
-
-            if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(
-                    mSubGroup, cbInfo.mPkgName)) {
-                return false;
-            }
-
-            if (!mLocationPermissionChecker.checkLocationPermission(
-                    cbInfo.mPkgName,
-                    "VcnStatusCallback" /* featureId */,
-                    cbInfo.mUid,
-                    null /* message */)) {
-                return false;
-            }
-            return true;
-        }
-
         @Override
         public void onEnteredSafeMode() {
             synchronized (mLock) {
@@ -838,7 +860,7 @@
 
                 // Notify all registered StatusCallbacks for this subGroup
                 for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
-                    if (isCallbackPermissioned(cbInfo)) {
+                    if (isCallbackPermissioned(cbInfo, mSubGroup)) {
                         Binder.withCleanCallingIdentity(
                                 () ->
                                         cbInfo.mCallback.onVcnStatusChanged(
@@ -862,7 +884,7 @@
 
                 // Notify all registered StatusCallbacks for this subGroup
                 for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
-                    if (isCallbackPermissioned(cbInfo)) {
+                    if (isCallbackPermissioned(cbInfo, mSubGroup)) {
                         Binder.withCleanCallingIdentity(
                                 () ->
                                         cbInfo.mCallback.onGatewayConnectionError(
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 5d89bf1..56aabc20 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -47,7 +47,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.security.Credentials;
-import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -60,6 +59,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
 import com.android.server.net.LockdownVpnTracker;
 
 import java.io.FileDescriptor;
@@ -83,7 +83,7 @@
     private final Dependencies mDeps;
 
     private final ConnectivityManager mCm;
-    private final KeyStore mKeyStore;
+    private final VpnProfileStore mVpnProfileStore;
     private final INetworkManagementService mNMS;
     private final INetd mNetd;
     private final UserManager mUserManager;
@@ -114,9 +114,9 @@
             return new HandlerThread("VpnManagerService");
         }
 
-        /** Returns the KeyStore instance to be used by this class. */
-        public KeyStore getKeyStore() {
-            return KeyStore.getInstance();
+        /** Return the VpnProfileStore to be used by this class */
+        public VpnProfileStore getVpnProfileStore() {
+            return new VpnProfileStore();
         }
 
         public INetd getNetd() {
@@ -135,7 +135,7 @@
         mHandlerThread = mDeps.makeHandlerThread();
         mHandlerThread.start();
         mHandler = mHandlerThread.getThreadHandler();
-        mKeyStore = mDeps.getKeyStore();
+        mVpnProfileStore = mDeps.getVpnProfileStore();
         mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mNMS = mDeps.getINetworkManagementService();
@@ -289,7 +289,7 @@
     public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
         final int user = UserHandle.getUserId(mDeps.getCallingUid());
         synchronized (mVpns) {
-            return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
+            return mVpns.get(user).provisionVpnProfile(packageName, profile);
         }
     }
 
@@ -307,7 +307,7 @@
     public void deleteVpnProfile(@NonNull String packageName) {
         final int user = UserHandle.getUserId(mDeps.getCallingUid());
         synchronized (mVpns) {
-            mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
+            mVpns.get(user).deleteVpnProfile(packageName);
         }
     }
 
@@ -325,7 +325,7 @@
         final int user = UserHandle.getUserId(mDeps.getCallingUid());
         synchronized (mVpns) {
             throwIfLockdownEnabled();
-            mVpns.get(user).startVpnProfile(packageName, mKeyStore);
+            mVpns.get(user).startVpnProfile(packageName);
         }
     }
 
@@ -358,7 +358,7 @@
         }
         synchronized (mVpns) {
             throwIfLockdownEnabled();
-            mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
+            mVpns.get(user).startLegacyVpn(profile, null /* underlying */, egress);
         }
     }
 
@@ -396,7 +396,7 @@
     }
 
     private boolean isLockdownVpnEnabled() {
-        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+        return mVpnProfileStore.get(Credentials.LOCKDOWN_VPN) != null;
     }
 
     @Override
@@ -417,14 +417,14 @@
                 return true;
             }
 
-            byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+            byte[] profileTag = mVpnProfileStore.get(Credentials.LOCKDOWN_VPN);
             if (profileTag == null) {
                 loge("Lockdown VPN configured but cannot be read from keystore");
                 return false;
             }
             String profileName = new String(profileTag);
             final VpnProfile profile = VpnProfile.decode(
-                    profileName, mKeyStore.get(Credentials.VPN + profileName));
+                    profileName, mVpnProfileStore.get(Credentials.VPN + profileName));
             if (profile == null) {
                 loge("Lockdown VPN configured invalid profile " + profileName);
                 setLockdownTracker(null);
@@ -437,7 +437,7 @@
                 return false;
             }
             setLockdownTracker(
-                    new LockdownVpnTracker(mContext, mHandler, mKeyStore, vpn,  profile));
+                    new LockdownVpnTracker(mContext, mHandler, vpn,  profile));
         }
 
         return true;
@@ -495,7 +495,7 @@
                 return false;
             }
 
-            return vpn.startAlwaysOnVpn(mKeyStore);
+            return vpn.startAlwaysOnVpn();
         }
     }
 
@@ -510,7 +510,7 @@
                 logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
-            return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
+            return vpn.isAlwaysOnPackageSupported(packageName);
         }
     }
 
@@ -531,11 +531,11 @@
                 logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
-            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist, mKeyStore)) {
+            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist)) {
                 return false;
             }
             if (!startAlwaysOnVpn(userId)) {
-                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+                vpn.setAlwaysOnPackage(null, false, null);
                 return false;
             }
         }
@@ -705,7 +705,8 @@
                 loge("Starting user already has a VPN");
                 return;
             }
-            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
+            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId,
+                    new VpnProfileStore());
             mVpns.put(userId, userVpn);
             if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
@@ -777,7 +778,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
                 log("Restarting always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.startAlwaysOnVpn(mKeyStore);
+                vpn.startAlwaysOnVpn();
             }
         }
     }
@@ -798,7 +799,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
                 log("Removing always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+                vpn.setAlwaysOnPackage(null, false, null);
             }
         }
     }
@@ -843,7 +844,7 @@
             if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    mKeyStore.delete(Credentials.LOCKDOWN_VPN);
+                    mVpnProfileStore.remove(Credentials.LOCKDOWN_VPN);
                     mLockdownEnabled = false;
                     setLockdownTracker(null);
                 } finally {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 9930eac..7375523 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -279,7 +279,7 @@
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mHandler = new MessageHandler(injector.getMessageHandlerLooper());
         mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
-        mAuthenticatorCache.setListener(this, null /* Handler */);
+        mAuthenticatorCache.setListener(this, mHandler);
 
         sThis.set(this);
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e5ef935..277cb8c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -86,6 +86,7 @@
 import android.app.ServiceStartArgs;
 import android.app.admin.DevicePolicyEventLogger;
 import android.app.compat.CompatChanges;
+import android.app.usage.UsageEvents;
 import android.appwidget.AppWidgetManagerInternal;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
@@ -2464,6 +2465,10 @@
                 s.setAllowedBgFgsStartsByBinding(true);
             }
 
+            if ((flags & Context.BIND_NOT_APP_COMPONENT_USAGE) != 0) {
+                s.isNotAppComponentUsage = true;
+            }
+
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app.mServices, c, true);
             }
@@ -3332,6 +3337,14 @@
             return msg;
         }
 
+        // Report usage if binding is from a different package except for explicitly exempted
+        // bindings
+        if (!r.appInfo.packageName.equals(r.mRecentCallingPackage)
+                && !r.isNotAppComponentUsage) {
+            mAm.mUsageStatsService.reportEvent(
+                    r.packageName, r.userId, UsageEvents.Event.APP_COMPONENT_USED);
+        }
+
         // Service is now being launched, its package can't be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
@@ -3841,6 +3854,8 @@
                     r.name.getClassName());
             stopServiceAndUpdateAllowlistManagerLocked(r);
             if (r.app.getThread() != null) {
+                // Bump the process to the top of LRU list
+                mAm.updateLruProcessLocked(r.app, false, null);
                 updateServiceForegroundLocked(r.app.mServices, false);
                 try {
                     bumpServiceExecutingLocked(r, false, "destroy");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7cd49497..874e527 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2684,6 +2684,11 @@
         }
         if (mUsageStatsService != null) {
             mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(), taskRoot);
+            if (event == Event.ACTIVITY_RESUMED) {
+                // Report component usage as an activity is an app component
+                mUsageStatsService.reportEvent(
+                        activity.getPackageName(), userId, Event.APP_COMPONENT_USED);
+            }
         }
         ContentCaptureManagerInternal contentCaptureService = mContentCaptureService;
         if (contentCaptureService != null && (event == Event.ACTIVITY_PAUSED
@@ -6099,6 +6104,10 @@
             updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
         }
 
+        // Report usage as process is persistent and being started.
+        mUsageStatsService.reportEvent(info.packageName, UserHandle.getUserId(app.uid),
+                Event.APP_COMPONENT_USED);
+
         // This package really, really can not be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
@@ -15179,8 +15188,8 @@
                             mFgsStartTempAllowList.add(changingUid, durationMs, reasonCode, reason,
                                     callingUid);
                         }
-                        setAppIdTempAllowlistStateLSP(changingUid, adding);
                     }
+                    setAppIdTempAllowlistStateLSP(changingUid, adding);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index c971bd2..5ad77a3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -168,6 +168,7 @@
     private int mTaskId;
     private boolean mIsTaskOverlay;
     private boolean mIsLockTask;
+    private boolean mAsync;
     private BroadcastOptions mBroadcastOptions;
 
     final boolean mDumping;
@@ -342,6 +343,7 @@
         mTaskId = INVALID_TASK_ID;
         mIsTaskOverlay = false;
         mIsLockTask = false;
+        mAsync = false;
         mBroadcastOptions = null;
 
         return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@@ -406,6 +408,8 @@
                         mBroadcastOptions = BroadcastOptions.makeBasic();
                     }
                     mBroadcastOptions.setBackgroundActivityStartsAllowed(true);
+                } else if (opt.equals("--async")) {
+                    mAsync = true;
                 } else {
                     return false;
                 }
@@ -756,7 +760,9 @@
         mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
                 requiredPermissions, android.app.AppOpsManager.OP_NONE, bundle, true, false,
                 mUserId);
-        receiver.waitForFinish();
+        if (!mAsync) {
+            receiver.waitForFinish();
+        }
         return 0;
     }
 
@@ -3180,13 +3186,17 @@
             pw.println("      Stop a Service.  Options are:");
             pw.println("      --user <USER_ID> | current: Specify which user to run as; if not");
             pw.println("          specified then run as the current user.");
-            pw.println("  broadcast [--user <USER_ID> | all | current] <INTENT>");
+            pw.println("  broadcast [--user <USER_ID> | all | current]");
+            pw.println("          [--receiver-permission <PERMISSION>]");
+            pw.println("          [--allow-background-activity-starts]");
+            pw.println("          [--async] <INTENT>");
             pw.println("      Send a broadcast Intent.  Options are:");
             pw.println("      --user <USER_ID> | all | current: Specify which user to send to; if not");
             pw.println("          specified then send to all users.");
             pw.println("      --receiver-permission <PERMISSION>: Require receiver to hold permission.");
             pw.println("      --allow-background-activity-starts: The receiver may start activities");
             pw.println("          even if in the background.");
+            pw.println("      --async: Send without waiting for the completion of the receiver.");
             pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
             pw.println("          [--user <USER_ID> | current]");
             pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 167c2b1..ce2852c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+
+import android.annotation.NonNull;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -25,7 +28,9 @@
 import android.hardware.power.stats.State;
 import android.hardware.power.stats.StateResidency;
 import android.hardware.power.stats.StateResidencyResult;
+import android.net.ConnectivityManager;
 import android.net.INetworkManagementEventObserver;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
@@ -77,8 +82,10 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ParseUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
+import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.net.BaseNetworkObserver;
 import com.android.server.pm.UserManagerInternal;
 
@@ -291,6 +298,23 @@
         return builder.toString();
     }
 
+    private ConnectivityManager.NetworkCallback mNetworkCallback =
+            new ConnectivityManager.NetworkCallback() {
+        @Override
+        public void onCapabilitiesChanged(@NonNull Network network,
+                @NonNull NetworkCapabilities networkCapabilities) {
+            final String state = networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                    ? "CONNECTED" : "SUSPENDED";
+            noteConnectivityChanged(NetworkCapabilitiesUtils.getDisplayTransport(
+                    networkCapabilities.getTransportTypes()), state);
+        }
+
+        @Override
+        public void onLost(Network network) {
+            noteConnectivityChanged(-1, "DISCONNECTED");
+        }
+    };
+
     BatteryStatsService(Context context, File systemDir, Handler handler) {
         // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
         mContext = context;
@@ -330,8 +354,10 @@
         mWorker.systemServicesReady();
         final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
         try {
             nms.registerObserver(mActivityChangeObserver);
+            cm.registerDefaultNetworkCallback(mNetworkCallback);
         } catch (RemoteException e) {
             Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
         }
@@ -346,6 +372,9 @@
         }
 
         Watchdog.getInstance().addMonitor(this);
+
+        final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler);
+        dataConnectionStats.startMonitoring();
     }
 
     private final class LocalService extends BatteryStatsInternal {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2906193..06cacc7 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -29,6 +29,7 @@
 import android.app.BroadcastOptions;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
+import android.app.usage.UsageEvents.Event;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.IIntentReceiver;
@@ -52,6 +53,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.permission.IPermissionManager;
+import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -1634,6 +1636,13 @@
                     brOptions.getTemporaryAppAllowlistReason());
         }
 
+        // Report that a component is used for explicit broadcasts.
+        if (!r.intent.isExcludingStopped() && r.curComponent != null
+                && !TextUtils.equals(r.curComponent.getPackageName(), r.callerPackage)) {
+            mService.mUsageStatsService.reportEvent(
+                    r.curComponent.getPackageName(), r.userId, Event.APP_COMPONENT_USED);
+        }
+
         // Broadcast is being executed, its package can't be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index f43c7f6..2c8794d 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -32,6 +32,7 @@
 import android.app.ApplicationExitInfo;
 import android.app.ContentProviderHolder;
 import android.app.IApplicationThread;
+import android.app.usage.UsageEvents.Event;
 import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -57,6 +58,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
@@ -412,6 +414,12 @@
                     final long origId = Binder.clearCallingIdentity();
 
                     try {
+                        if (!TextUtils.equals(cpr.appInfo.packageName, callingPackage)) {
+                            // Report component used since a content provider is being bound.
+                            mService.mUsageStatsService.reportEvent(
+                                    cpr.appInfo.packageName, userId, Event.APP_COMPONENT_USED);
+                        }
+
                         // Content provider is now in use, its package can't be stopped.
                         try {
                             checkTime(startTime,
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 60b2467..984fe40 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -17,6 +17,8 @@
 package com.android.server.am;
 
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerWhitelistManager.REASON_PRE_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
@@ -117,9 +119,9 @@
             duration = amInternal.getBootTimeTempAllowListDuration();
         }
         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
-        bOptions.setTemporaryAppWhitelistDuration(
-                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                duration);
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                REASON_PRE_BOOT_COMPLETED, "");
         synchronized (mService) {
             mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
                     null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 3258f8a..d03a47a 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -329,6 +329,22 @@
             info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
         }
 
+        // Retrieve controller with max ANR delay from AnrControllers
+        // Note that we retrieve the controller before dumping stacks because dumping stacks can
+        // take a few seconds, after which the cause of the ANR delay might have completed and
+        // there might no longer be a valid ANR controller to cancel the dialog in that case
+        AnrController anrController = mService.mActivityTaskManager.getAnrController(aInfo);
+        long anrDialogDelayMs = 0;
+        if (anrController != null) {
+            String packageName = aInfo.packageName;
+            int uid = aInfo.uid;
+            anrDialogDelayMs = anrController.getAnrDelayMillis(packageName, uid);
+            // Might execute an async binder call to a system app to show an interim
+            // ANR progress UI
+            anrController.onAnrDelayStarted(packageName, uid);
+            Slog.i(TAG, "ANR delay of " + anrDialogDelayMs + "ms started for " + packageName);
+        }
+
         StringBuilder report = new StringBuilder();
         report.append(MemoryPressureUtil.currentPsiState());
         ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
@@ -417,20 +433,6 @@
             return;
         }
 
-        // Retrieve max ANR delay from AnrControllers without the mService lock since the
-        // controllers might in turn call into apps
-        AnrController anrController = mService.mActivityTaskManager.getAnrController(aInfo);
-        long anrDialogDelayMs = 0;
-        if (anrController != null) {
-            String packageName = aInfo.packageName;
-            int uid = aInfo.uid;
-            anrDialogDelayMs = anrController.getAnrDelayMillis(packageName, uid);
-            // Might execute an async binder call to a system app to show an interim
-            // ANR progress UI
-            anrController.onAnrDelayStarted(packageName, uid);
-            Slog.i(TAG, "ANR delay of " + anrDialogDelayMs + "ms started for " + packageName);
-        }
-
         synchronized (mService) {
             // mBatteryStatsService can be null if the AMS is constructed with injector only. This
             // will only happen in tests.
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 3ab95d1..9cd9902 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -107,6 +107,7 @@
     boolean delayed;        // are we waiting to start this service in the background?
     boolean fgRequired;     // is the service required to go foreground after starting?
     boolean fgWaiting;      // is a timeout for going foreground already scheduled?
+    boolean isNotAppComponentUsage; // is service binding not considered component/package usage?
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
     Notification foregroundNoti; // Notification record of foreground state.
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6dd78e7..caf2510 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -27,6 +27,9 @@
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
 
@@ -74,6 +77,7 @@
 import android.os.IUserManager;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerWhitelistManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -522,7 +526,8 @@
                 mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
                         new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                         AppOpsManager.OP_NONE,
-                        getTemporaryAppWhitelistBroadcastOptions().toBundle(), true,
+                        getTemporaryAppAllowlistBroadcastOptions(REASON_LOCKED_BOOT_COMPLETED)
+                                .toBundle(), true,
                         false, MY_PID, SYSTEM_UID,
                         Binder.getCallingUid(), Binder.getCallingPid(), userId);
             }
@@ -770,9 +775,8 @@
                     }, 0, null, null,
                     new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                     AppOpsManager.OP_NONE,
-                    getTemporaryAppWhitelistBroadcastOptions().toBundle(), true,
-                    false, MY_PID, SYSTEM_UID,
-                    callingUid, callingPid, userId);
+                    getTemporaryAppAllowlistBroadcastOptions(REASON_BOOT_COMPLETED).toBundle(),
+                    true, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
         });
     }
 
@@ -2811,7 +2815,8 @@
         }
     }
 
-    private BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
+    private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+            @PowerWhitelistManager.ReasonCode int reasonCode) {
         long duration = 10_000;
         final ActivityManagerInternal amInternal =
                 LocalServices.getService(ActivityManagerInternal.class);
@@ -2819,9 +2824,8 @@
             duration = amInternal.getBootTimeTempAllowListDuration();
         }
         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
-        bOptions.setTemporaryAppWhitelistDuration(
-                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                duration);
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, reasonCode, "");
         return bOptions;
     }
 
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 44dcc20..11125dd 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -843,11 +843,15 @@
         public void accessed(int proxyUid, @Nullable String proxyPackageName,
                 @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
                 @OpFlags int flags) {
-            accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
+            long accessTime = System.currentTimeMillis();
+            accessed(accessTime, -1, proxyUid, proxyPackageName,
                     proxyAttributionTag, uidState, flags);
 
             mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
                     tag, uidState, flags);
+
+            mHistoricalRegistry.mDiscreteRegistry.recordDiscreteAccess(parent.uid,
+                    parent.packageName, parent.op, tag, flags, uidState, accessTime, -1);
         }
 
         /**
@@ -1004,8 +1008,10 @@
                 OpEventProxyInfo proxyCopy = event.getProxy() != null
                         ? new OpEventProxyInfo(event.getProxy()) : null;
 
+                long accessDurationMillis =
+                        SystemClock.elapsedRealtime() - event.getStartElapsedTime();
                 NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
-                        SystemClock.elapsedRealtime() - event.getStartElapsedTime(), proxyCopy);
+                        accessDurationMillis, proxyCopy);
                 mAccessEvents.put(makeKey(event.getUidState(), event.getFlags()),
                         finishedEvent);
 
@@ -1013,6 +1019,10 @@
                         parent.packageName, tag, event.getUidState(),
                         event.getFlags(), finishedEvent.getDuration());
 
+                mHistoricalRegistry.mDiscreteRegistry.recordDiscreteAccess(parent.uid,
+                        parent.packageName, parent.op, tag, event.getFlags(), event.getUidState(),
+                        event.getStartTime(), accessDurationMillis);
+
                 mInProgressStartOpEventPool.release(event);
 
                 if (mInProgressEvents.isEmpty()) {
@@ -2087,8 +2097,8 @@
 
     @Override
     public void getHistoricalOps(int uid, String packageName, String attributionTag,
-            List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
-            int flags, RemoteCallback callback) {
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback) {
         PackageManager pm = mContext.getPackageManager();
 
         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
@@ -2120,14 +2130,14 @@
 
         // Must not hold the appops lock
         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
-                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, filter,
-                beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
+                filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
     }
 
     @Override
     public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
-            List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
-            int flags, RemoteCallback callback) {
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback) {
         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
                 beginTimeMillis, endTimeMillis, flags);
         Objects.requireNonNull(callback, "callback cannot be null");
@@ -2140,7 +2150,7 @@
 
         // Must not hold the appops lock
         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
-                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray,
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
                 filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
     }
 
@@ -4759,6 +4769,7 @@
                 mFile.failWrite(stream);
             }
         }
+        mHistoricalRegistry.mDiscreteRegistry.writeAndClearAccessHistory();
     }
 
     static class Shell extends ShellCommand {
@@ -6115,6 +6126,7 @@
                 "clearHistory");
         // Must not hold the appops lock
         mHistoricalRegistry.clearHistory();
+        mHistoricalRegistry.mDiscreteRegistry.clearHistory();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
new file mode 100644
index 0000000..7699045
--- /dev/null
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
+import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
+import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
+import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_FLAG_SELF;
+import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+
+import static java.lang.Math.max;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class manages information about recent accesses to ops for
+ * permission usage timeline.
+ *
+ * The timeline history is kept for limited time (initial default is 24 hours) and
+ * discarded after that.
+ *
+ * Every time state is saved (default is 30 minutes), memory state is dumped to a
+ * new file and memory state is cleared. Files older than time limit are deleted
+ * during the process.
+ *
+ * When request comes in, files are read and requested information is collected
+ * and delivered.
+ */
+
+final class DiscreteRegistry {
+    static final String TIMELINE_FILE_SUFFIX = "tl";
+    private static final String TAG = DiscreteRegistry.class.getSimpleName();
+
+    private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis();
+    private static final String TAG_HISTORY = "h";
+    private static final String ATTR_VERSION = "v";
+    private static final int CURRENT_VERSION = 1;
+
+    private static final String TAG_UID = "u";
+    private static final String ATTR_UID = "ui";
+
+    private static final String TAG_PACKAGE = "p";
+    private static final String ATTR_PACKAGE_NAME = "pn";
+
+    private static final String TAG_OP = "o";
+    private static final String ATTR_OP_ID = "op";
+
+    private static final String TAG_TAG = "a";
+    private static final String ATTR_TAG = "at";
+
+    private static final String TAG_ENTRY = "e";
+    private static final String ATTR_NOTE_TIME = "nt";
+    private static final String ATTR_NOTE_DURATION = "nd";
+    private static final String ATTR_UID_STATE = "us";
+    private static final String ATTR_FLAGS = "f";
+
+    // Lock for read/write access to on disk state
+    private final Object mOnDiskLock = new Object();
+
+    //Lock for read/write access to in memory state
+    private final @NonNull Object mInMemoryLock;
+
+    @GuardedBy("mOnDiskLock")
+    private final File mDiscreteAccessDir;
+
+    @GuardedBy("mInMemoryLock")
+    private DiscreteOps mDiscreteOps;
+
+    DiscreteRegistry(Object inMemoryLock) {
+        mInMemoryLock = inMemoryLock;
+        mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"),
+                "discrete");
+        createDiscreteAccessDir();
+        mDiscreteOps = new DiscreteOps();
+    }
+
+    private void createDiscreteAccessDir() {
+        if (!mDiscreteAccessDir.exists()) {
+            if (!mDiscreteAccessDir.mkdirs()) {
+                Slog.e(TAG, "Failed to create DiscreteRegistry directory");
+            }
+            FileUtils.setPermissions(mDiscreteAccessDir.getPath(),
+                    FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
+        }
+    }
+
+    void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag,
+            @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime,
+            long accessDuration) {
+        if (!isDiscreteOp(op, uid, flags)) {
+            return;
+        }
+        synchronized (mInMemoryLock) {
+            mDiscreteOps.addDiscreteAccess(op, uid, packageName, attributionTag, flags, uidState,
+                    accessTime, accessDuration);
+        }
+    }
+
+    void writeAndClearAccessHistory() {
+        synchronized (mOnDiskLock) {
+            final File[] files = mDiscreteAccessDir.listFiles();
+            if (files != null && files.length > 0) {
+                for (File f : files) {
+                    final String fileName = f.getName();
+                    if (!fileName.endsWith(TIMELINE_FILE_SUFFIX)) {
+                        continue;
+                    }
+                    try {
+                        long timestamp = Long.valueOf(fileName.substring(0,
+                                fileName.length() - TIMELINE_FILE_SUFFIX.length()));
+                        if (Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
+                                ChronoUnit.MILLIS).toEpochMilli() > timestamp) {
+                            f.delete();
+                            Slog.e(TAG, "Deleting file " + fileName);
+
+                        }
+                    } catch (Throwable t) {
+                        Slog.e(TAG, "Error while cleaning timeline files: " + t.getMessage() + " "
+                                + t.getStackTrace());
+                    }
+                }
+            }
+        }
+        DiscreteOps discreteOps;
+        synchronized (mInMemoryLock) {
+            discreteOps = mDiscreteOps;
+            mDiscreteOps = new DiscreteOps();
+        }
+        if (discreteOps.isEmpty()) {
+            return;
+        }
+        long currentTimeStamp = Instant.now().toEpochMilli();
+        try {
+            final File file = new File(mDiscreteAccessDir, currentTimeStamp + TIMELINE_FILE_SUFFIX);
+            discreteOps.writeToFile(file);
+        } catch (Throwable t) {
+            Slog.e(TAG,
+                    "Error writing timeline state: " + t.getMessage() + " "
+                            + Arrays.toString(t.getStackTrace()));
+        }
+    }
+
+    void getHistoricalDiscreteOps(AppOpsManager.HistoricalOps result, long beginTimeMillis,
+            long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
+            @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+            @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+        writeAndClearAccessHistory();
+        DiscreteOps discreteOps = new DiscreteOps();
+        readDiscreteOpsFromDisk(discreteOps, beginTimeMillis, endTimeMillis, filter, uidFilter,
+                packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
+        discreteOps.applyToHistoricalOps(result);
+        return;
+    }
+
+    private void readDiscreteOpsFromDisk(DiscreteOps discreteOps, long beginTimeMillis,
+            long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
+            @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+            @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+        synchronized (mOnDiskLock) {
+            long historyBeginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
+                    ChronoUnit.MILLIS).toEpochMilli();
+            if (historyBeginTimeMillis > endTimeMillis) {
+                return;
+            }
+            beginTimeMillis = max(beginTimeMillis, historyBeginTimeMillis);
+
+            final File[] files = mDiscreteAccessDir.listFiles();
+            if (files != null && files.length > 0) {
+                for (File f : files) {
+                    final String fileName = f.getName();
+                    if (!fileName.endsWith(TIMELINE_FILE_SUFFIX)) {
+                        continue;
+                    }
+                    long timestamp = Long.valueOf(fileName.substring(0,
+                            fileName.length() - TIMELINE_FILE_SUFFIX.length()));
+                    if (timestamp < beginTimeMillis) {
+                        continue;
+                    }
+                    discreteOps.readFromFile(f, beginTimeMillis, endTimeMillis, filter, uidFilter,
+                            packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
+                }
+            }
+        }
+    }
+
+    void clearHistory() {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                mDiscreteOps = new DiscreteOps();
+            }
+            FileUtils.deleteContentsAndDir(mDiscreteAccessDir);
+            createDiscreteAccessDir();
+        }
+    }
+
+    public static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) {
+        if (!isDiscreteOp(op)) {
+            return false;
+        }
+        if (!isDiscreteUid(uid)) {
+            return false;
+        }
+        if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) == 0) {
+            return false;
+        }
+        return true;
+    }
+
+    static boolean isDiscreteOp(int op) {
+        if (op != OP_CAMERA && op != OP_RECORD_AUDIO && op != OP_FINE_LOCATION
+                && op != OP_COARSE_LOCATION) {
+            return false;
+        }
+        return true;
+    }
+
+    static boolean isDiscreteUid(int uid) {
+        if (uid < Process.FIRST_APPLICATION_UID) {
+            return false;
+        }
+        return true;
+    }
+
+    private final class DiscreteOps {
+        ArrayMap<Integer, DiscreteUidOps> mUids;
+
+        DiscreteOps() {
+            mUids = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(int op, int uid, @NonNull String packageName,
+                @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
+                @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) {
+            getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
+                    uidState, accessTime, accessDuration);
+        }
+
+        private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
+            int nUids = mUids.size();
+            for (int i = 0; i < nUids; i++) {
+                mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i));
+            }
+        }
+
+        private void writeToFile(File f) throws Exception {
+            FileOutputStream stream = new FileOutputStream(f);
+            TypedXmlSerializer out = Xml.resolveSerializer(stream);
+
+            out.startDocument(null, true);
+            out.startTag(null, TAG_HISTORY);
+            out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
+
+            int nUids = mUids.size();
+            for (int i = 0; i < nUids; i++) {
+                out.startTag(null, TAG_UID);
+                out.attributeInt(null, ATTR_UID, mUids.keyAt(i));
+                mUids.valueAt(i).serialize(out);
+                out.endTag(null, TAG_UID);
+            }
+            out.endTag(null, TAG_HISTORY);
+            out.endDocument();
+            stream.close();
+        }
+
+        private DiscreteUidOps getOrCreateDiscreteUidOps(int uid) {
+            DiscreteUidOps result = mUids.get(uid);
+            if (result == null) {
+                result = new DiscreteUidOps();
+                mUids.put(uid, result);
+            }
+            return result;
+        }
+
+        boolean isEmpty() {
+            return mUids.isEmpty();
+        }
+
+        private void readFromFile(File f, long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                int uidFilter, @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+                @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+            try {
+                FileInputStream stream = new FileInputStream(f);
+                TypedXmlPullParser parser = Xml.resolvePullParser(stream);
+                XmlUtils.beginDocument(parser, TAG_HISTORY);
+
+                // We haven't released version 1 and have more detailed
+                // accounting - just nuke the current state
+                final int version = parser.getAttributeInt(null, ATTR_VERSION);
+                if (version != CURRENT_VERSION) {
+                    throw new IllegalStateException("Dropping unsupported discrete history " + f);
+                }
+
+                int depth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, depth)) {
+                    if (TAG_UID.equals(parser.getName())) {
+                        int uid = parser.getAttributeInt(null, ATTR_UID, -1);
+                        if ((filter & FILTER_BY_UID) != 0 && uid != uidFilter) {
+                            continue;
+                        }
+                        getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis,
+                                endTimeMillis, filter, packageNameFilter, opNamesFilter,
+                                attributionTagFilter, flagsFilter);
+                    }
+                }
+            } catch (Throwable t) {
+                Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " "
+                        + Arrays.toString(t.getStackTrace()));
+            }
+
+        }
+    }
+
+    private final class DiscreteUidOps {
+        ArrayMap<String, DiscretePackageOps> mPackages;
+
+        DiscreteUidOps() {
+            mPackages = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(int op, @NonNull String packageName, @Nullable String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
+                long accessTime, long accessDuration) {
+            getOrCreateDiscretePackageOps(packageName).addDiscreteAccess(op, attributionTag, flags,
+                    uidState, accessTime, accessDuration);
+        }
+
+        private DiscretePackageOps getOrCreateDiscretePackageOps(String packageName) {
+            DiscretePackageOps result = mPackages.get(packageName);
+            if (result == null) {
+                result = new DiscretePackageOps();
+                mPackages.put(packageName, result);
+            }
+            return result;
+        }
+
+        private void applyToHistory(AppOpsManager.HistoricalOps result, int uid) {
+            int nPackages = mPackages.size();
+            for (int i = 0; i < nPackages; i++) {
+                mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i));
+            }
+        }
+
+        void serialize(TypedXmlSerializer out) throws Exception {
+            int nPackages = mPackages.size();
+            for (int i = 0; i < nPackages; i++) {
+                out.startTag(null, TAG_PACKAGE);
+                out.attribute(null, ATTR_PACKAGE_NAME, mPackages.keyAt(i));
+                mPackages.valueAt(i).serialize(out);
+                out.endTag(null, TAG_PACKAGE);
+            }
+        }
+
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis,
+                long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String packageNameFilter,
+                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+            int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_PACKAGE.equals(parser.getName())) {
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                    if ((filter & FILTER_BY_PACKAGE_NAME) != 0
+                            && !packageName.equals(packageNameFilter)) {
+                        continue;
+                    }
+                    getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis,
+                            endTimeMillis, filter, opNamesFilter, attributionTagFilter,
+                            flagsFilter);
+                }
+            }
+        }
+    }
+
+    private final class DiscretePackageOps {
+        ArrayMap<Integer, DiscreteOp> mPackageOps;
+
+        DiscretePackageOps() {
+            mPackageOps = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(int op, @Nullable String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
+                long accessTime, long accessDuration) {
+            getOrCreateDiscreteOp(op).addDiscreteAccess(attributionTag, flags, uidState, accessTime,
+                    accessDuration);
+        }
+
+        private DiscreteOp getOrCreateDiscreteOp(int op) {
+            DiscreteOp result = mPackageOps.get(op);
+            if (result == null) {
+                result = new DiscreteOp();
+                mPackageOps.put(op, result);
+            }
+            return result;
+        }
+
+        private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+                @NonNull String packageName) {
+            int nPackageOps = mPackageOps.size();
+            for (int i = 0; i < nPackageOps; i++) {
+                mPackageOps.valueAt(i).applyToHistory(result, uid, packageName,
+                        mPackageOps.keyAt(i));
+            }
+        }
+
+        void serialize(TypedXmlSerializer out) throws Exception {
+            int nOps = mPackageOps.size();
+            for (int i = 0; i < nOps; i++) {
+                out.startTag(null, TAG_OP);
+                out.attributeInt(null, ATTR_OP_ID, mPackageOps.keyAt(i));
+                mPackageOps.valueAt(i).serialize(out);
+                out.endTag(null, TAG_OP);
+            }
+        }
+
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+            int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_OP.equals(parser.getName())) {
+                    int op = parser.getAttributeInt(null, ATTR_OP_ID);
+                    if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter,
+                            AppOpsManager.opToPublicName(op))) {
+                        continue;
+                    }
+                    getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis, endTimeMillis,
+                            filter, attributionTagFilter, flagsFilter);
+                }
+            }
+        }
+    }
+
+    private final class DiscreteOp {
+        ArrayMap<String, List<DiscreteOpEvent>> mAttributedOps;
+
+        DiscreteOp() {
+            mAttributedOps = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(@Nullable String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
+                long accessTime, long accessDuration) {
+            List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList(
+                    attributionTag);
+            accessTime = Instant.ofEpochMilli(accessTime).truncatedTo(
+                    ChronoUnit.MINUTES).toEpochMilli();
+
+            int nAttributedOps = attributedOps.size();
+            for (int i = nAttributedOps - 1; i >= 0; i--) {
+                DiscreteOpEvent previousOp = attributedOps.get(i);
+                if (previousOp.mNoteTime < accessTime) {
+                    break;
+                }
+                if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) {
+                    return;
+                }
+            }
+            attributedOps.add(new DiscreteOpEvent(accessTime, accessDuration, uidState, flags));
+        }
+
+        private List<DiscreteOpEvent> getOrCreateDiscreteOpEventsList(String attributionTag) {
+            List<DiscreteOpEvent> result = mAttributedOps.get(attributionTag);
+            if (result == null) {
+                result = new ArrayList<>();
+                mAttributedOps.put(attributionTag, result);
+            }
+            return result;
+        }
+
+        private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+                @NonNull String packageName, int op) {
+            int nOps = mAttributedOps.size();
+            for (int i = 0; i < nOps; i++) {
+                String tag = mAttributedOps.keyAt(i);
+                List<DiscreteOpEvent> events = mAttributedOps.valueAt(i);
+                int nEvents = events.size();
+                for (int j = 0; j < nEvents; j++) {
+                    DiscreteOpEvent event = events.get(j);
+                    result.addDiscreteAccess(op, uid, packageName, tag, event.mUidState,
+                            event.mOpFlag, event.mNoteTime, event.mNoteDuration);
+                }
+            }
+        }
+
+        void serialize(TypedXmlSerializer out) throws Exception {
+            int nAttributions = mAttributedOps.size();
+            for (int i = 0; i < nAttributions; i++) {
+                out.startTag(null, TAG_TAG);
+                String tag = mAttributedOps.keyAt(i);
+                if (tag != null) {
+                    out.attribute(null, ATTR_TAG, mAttributedOps.keyAt(i));
+                }
+                List<DiscreteOpEvent> ops = mAttributedOps.valueAt(i);
+                int nOps = ops.size();
+                for (int j = 0; j < nOps; j++) {
+                    out.startTag(null, TAG_ENTRY);
+                    ops.get(j).serialize(out);
+                    out.endTag(null, TAG_ENTRY);
+                }
+                out.endTag(null, TAG_TAG);
+            }
+        }
+
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                if (TAG_TAG.equals(parser.getName())) {
+                    String attributionTag = parser.getAttributeValue(null, ATTR_TAG);
+                    if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !attributionTag.equals(
+                            attributionTagFilter)) {
+                        continue;
+                    }
+                    List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(
+                            attributionTag);
+                    int innerDepth = parser.getDepth();
+                    while (XmlUtils.nextElementWithin(parser, innerDepth)) {
+                        if (TAG_ENTRY.equals(parser.getName())) {
+                            long noteTime = parser.getAttributeLong(null, ATTR_NOTE_TIME);
+                            long noteDuration = parser.getAttributeLong(null, ATTR_NOTE_DURATION,
+                                    -1);
+                            int uidState = parser.getAttributeInt(null, ATTR_UID_STATE);
+                            int opFlags = parser.getAttributeInt(null, ATTR_FLAGS);
+                            if ((flagsFilter & opFlags) == 0) {
+                                continue;
+                            }
+                            if ((noteTime + noteDuration < beginTimeMillis
+                                    && noteTime > endTimeMillis)) {
+                                continue;
+                            }
+                            DiscreteOpEvent event = new DiscreteOpEvent(noteTime, noteDuration,
+                                    uidState, opFlags);
+                            events.add(event);
+                        }
+                    }
+                    Collections.sort(events, (a, b) -> a.mNoteTime < b.mNoteTime ? -1
+                            : (a.mNoteTime == b.mNoteTime ? 0 : 1));
+                }
+            }
+        }
+    }
+
+    private final class DiscreteOpEvent {
+        final long mNoteTime;
+        final long mNoteDuration;
+        final @AppOpsManager.UidState int mUidState;
+        final @AppOpsManager.OpFlags int mOpFlag;
+
+        DiscreteOpEvent(long noteTime, long noteDuration, @AppOpsManager.UidState int uidState,
+                @AppOpsManager.OpFlags int opFlag) {
+            mNoteTime = noteTime;
+            mNoteDuration = noteDuration;
+            mUidState = uidState;
+            mOpFlag = opFlag;
+        }
+
+        private void serialize(TypedXmlSerializer out) throws Exception {
+            out.attributeLong(null, ATTR_NOTE_TIME, mNoteTime);
+            if (mNoteDuration != -1) {
+                out.attributeLong(null, ATTR_NOTE_DURATION, mNoteDuration);
+            }
+            out.attributeInt(null, ATTR_UID_STATE, mUidState);
+            out.attributeInt(null, ATTR_FLAGS, mOpFlag);
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 17fd32c..1c43fed 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -19,6 +19,8 @@
 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
 import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.HISTORY_FLAG_AGGREGATE;
+import static android.app.AppOpsManager.HISTORY_FLAG_DISCRETE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +32,7 @@
 import android.app.AppOpsManager.HistoricalPackageOps;
 import android.app.AppOpsManager.HistoricalUidOps;
 import android.app.AppOpsManager.OpFlags;
+import android.app.AppOpsManager.OpHistoryFlags;
 import android.app.AppOpsManager.UidState;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
@@ -61,9 +64,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -71,7 +72,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -85,7 +85,7 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * This class managers historical app op state. This includes reading, persistence,
+ * This class manages historical app op state. This includes reading, persistence,
  * accounting, querying.
  * <p>
  * The history is kept forever in multiple files. Each file time contains the
@@ -138,6 +138,8 @@
     private static final String PARAMETER_ASSIGNMENT = "=";
     private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
 
+    volatile @NonNull DiscreteRegistry mDiscreteRegistry;
+
     @GuardedBy("mLock")
     private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
 
@@ -199,6 +201,7 @@
 
     HistoricalRegistry(@NonNull Object lock) {
         mInMemoryLock = lock;
+        mDiscreteRegistry = new DiscreteRegistry(lock);
     }
 
     HistoricalRegistry(@NonNull HistoricalRegistry other) {
@@ -352,36 +355,49 @@
         }
     }
 
-    void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+    void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
             @Nullable String attributionTag, @Nullable String[] opNames,
-            @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
-            @OpFlags int flags, @NonNull RemoteCallback callback) {
+            @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
+            long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
+            @NonNull RemoteCallback callback) {
         if (!isApiEnabled()) {
             callback.sendResult(new Bundle());
             return;
         }
 
-        synchronized (mOnDiskLock) {
-            synchronized (mInMemoryLock) {
-                if (!isPersistenceInitializedMLocked()) {
-                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
-                    callback.sendResult(new Bundle());
-                    return;
+        final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
+
+        if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
+            synchronized (mOnDiskLock) {
+                synchronized (mInMemoryLock) {
+                    if (!isPersistenceInitializedMLocked()) {
+                        Slog.e(LOG_TAG, "Interaction before persistence initialized");
+                        callback.sendResult(new Bundle());
+                        return;
+                    }
+                    mPersistence.collectHistoricalOpsDLocked(result, uid, packageName,
+                            attributionTag,
+                            opNames, filter, beginTimeMillis, endTimeMillis, flags);
+
                 }
-                final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
-                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
-                        opNames, filter, beginTimeMillis, endTimeMillis, flags);
-                final Bundle payload = new Bundle();
-                payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
-                callback.sendResult(payload);
             }
         }
+
+        if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
+            mDiscreteRegistry.getHistoricalDiscreteOps(result, beginTimeMillis, endTimeMillis,
+                    filter, uid, packageName, opNames, attributionTag,
+                    flags);
+        }
+
+        final Bundle payload = new Bundle();
+        payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+        callback.sendResult(payload);
     }
 
-    void getHistoricalOps(int uid, @NonNull String packageName, @Nullable String attributionTag,
-            @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
-            long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
-            @NonNull RemoteCallback callback) {
+    void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag,
+            @Nullable String[] opNames, @OpHistoryFlags int historyFlags,
+            @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
+            @OpFlags int flags, @NonNull RemoteCallback callback) {
         if (!isApiEnabled()) {
             callback.sendResult(new Bundle());
             return;
@@ -392,6 +408,8 @@
             endTimeMillis = currentTimeMillis;
         }
 
+        final Bundle payload = new Bundle();
+
         // Argument times are based off epoch start while our internal store is
         // based off now, so take this into account.
         final long inMemoryAdjBeginTimeMillis = Math.max(currentTimeMillis - endTimeMillis, 0);
@@ -399,55 +417,63 @@
         final HistoricalOps result = new HistoricalOps(inMemoryAdjBeginTimeMillis,
                 inMemoryAdjEndTimeMillis);
 
-        synchronized (mOnDiskLock) {
-            final List<HistoricalOps> pendingWrites;
-            final HistoricalOps currentOps;
-            boolean collectOpsFromDisk;
-
-            synchronized (mInMemoryLock) {
-                if (!isPersistenceInitializedMLocked()) {
-                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
-                    callback.sendResult(new Bundle());
-                    return;
-                }
-
-                currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
-                if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
-                        || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
-                    // Some of the current batch falls into the query, so extract that.
-                    final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
-                    currentOpsCopy.filter(uid, packageName, attributionTag, opNames, filter,
-                            inMemoryAdjBeginTimeMillis, inMemoryAdjEndTimeMillis);
-                    result.merge(currentOpsCopy);
-                }
-                pendingWrites = new ArrayList<>(mPendingWrites);
-                mPendingWrites.clear();
-                collectOpsFromDisk = inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis();
-            }
-
-            // If the query was only for in-memory state - done.
-            if (collectOpsFromDisk) {
-                // If there is a write in flight we need to force it now
-                persistPendingHistory(pendingWrites);
-                // Collect persisted state.
-                final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
-                        - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
-                final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
-                        - onDiskAndInMemoryOffsetMillis, 0);
-                final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
-                        - onDiskAndInMemoryOffsetMillis, 0);
-                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
-                        opNames, filter, onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis, flags);
-            }
-
-            // Rebase the result time to be since epoch.
-            result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
-
-            // Send back the result.
-            final Bundle payload = new Bundle();
-            payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
-            callback.sendResult(payload);
+        if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
+            mDiscreteRegistry.getHistoricalDiscreteOps(result, beginTimeMillis, endTimeMillis,
+                    filter, uid, packageName, opNames, attributionTag, flags);
         }
+
+        if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
+            synchronized (mOnDiskLock) {
+                final List<HistoricalOps> pendingWrites;
+                final HistoricalOps currentOps;
+                boolean collectOpsFromDisk;
+
+                synchronized (mInMemoryLock) {
+                    if (!isPersistenceInitializedMLocked()) {
+                        Slog.e(LOG_TAG, "Interaction before persistence initialized");
+                        callback.sendResult(new Bundle());
+                        return;
+                    }
+
+                    currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
+                    if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
+                            || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
+                        // Some of the current batch falls into the query, so extract that.
+                        final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
+                        currentOpsCopy.filter(uid, packageName, attributionTag, opNames,
+                                historyFlags, filter, inMemoryAdjBeginTimeMillis,
+                                inMemoryAdjEndTimeMillis);
+                        result.merge(currentOpsCopy);
+                    }
+                    pendingWrites = new ArrayList<>(mPendingWrites);
+                    mPendingWrites.clear();
+                    collectOpsFromDisk = inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis();
+                }
+
+                // If the query was only for in-memory state - done.
+                if (collectOpsFromDisk) {
+                    // If there is a write in flight we need to force it now
+                    persistPendingHistory(pendingWrites);
+                    // Collect persisted state.
+                    final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
+                            - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
+                    final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
+                            - onDiskAndInMemoryOffsetMillis, 0);
+                    final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
+                            - onDiskAndInMemoryOffsetMillis, 0);
+                    mPersistence.collectHistoricalOpsDLocked(result, uid, packageName,
+                            attributionTag,
+                            opNames, filter, onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis,
+                            flags);
+                }
+            }
+        }
+        // Rebase the result time to be since epoch.
+        result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
+
+        // Send back the result.
+        payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+        callback.sendResult(payload);
     }
 
     void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
@@ -692,6 +718,7 @@
             }
             persistPendingHistory(pendingWrites);
         }
+        mDiscreteRegistry.writeAndClearAccessHistory();
     }
 
     private void persistPendingHistory(@NonNull List<HistoricalOps> pendingWrites) {
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index e19745e..050b28b 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -33,6 +33,7 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.IAuthService;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -337,6 +338,168 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public CharSequence getButtonLabel(
+                int userId,
+                String opPackageName,
+                @Authenticators.Types int authenticators) throws RemoteException {
+
+            // Only allow internal clients to call getButtonLabel with a different userId.
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            if (userId != callingUserId) {
+                checkInternalPermission();
+            } else {
+                checkPermission();
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                @BiometricAuthenticator.Modality final int modality =
+                        mBiometricService.getCurrentModality(
+                                opPackageName, userId, callingUserId, authenticators);
+
+                final String result;
+                switch (getCredentialBackupModality(modality)) {
+                    case BiometricAuthenticator.TYPE_NONE:
+                        result = null;
+                        break;
+                    case BiometricAuthenticator.TYPE_CREDENTIAL:
+                        result = getContext().getString(R.string.screen_lock_app_setting_name);
+                        break;
+                    case BiometricAuthenticator.TYPE_FINGERPRINT:
+                        result = getContext().getString(R.string.fingerprint_app_setting_name);
+                        break;
+                    case BiometricAuthenticator.TYPE_FACE:
+                        result = getContext().getString(R.string.face_app_setting_name);
+                        break;
+                    default:
+                        result = getContext().getString(R.string.biometric_app_setting_name);
+                        break;
+                }
+
+                return result;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public CharSequence getPromptMessage(
+                int userId,
+                String opPackageName,
+                @Authenticators.Types int authenticators) throws RemoteException {
+
+            // Only allow internal clients to call getButtonLabel with a different userId.
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            if (userId != callingUserId) {
+                checkInternalPermission();
+            } else {
+                checkPermission();
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                @BiometricAuthenticator.Modality final int modality =
+                        mBiometricService.getCurrentModality(
+                                opPackageName, userId, callingUserId, authenticators);
+
+                final String result;
+                switch (getCredentialBackupModality(modality)) {
+                    case BiometricAuthenticator.TYPE_NONE:
+                        result = null;
+                        break;
+                    case BiometricAuthenticator.TYPE_CREDENTIAL:
+                        result = getContext().getString(
+                                R.string.screen_lock_dialog_default_subtitle);
+                        break;
+                    case BiometricAuthenticator.TYPE_FINGERPRINT:
+                        result = getContext().getString(
+                                R.string.fingerprint_dialog_default_subtitle);
+                        break;
+                    case BiometricAuthenticator.TYPE_FACE:
+                        result = getContext().getString(R.string.face_dialog_default_subtitle);
+                        break;
+                    default:
+                        result = getContext().getString(R.string.biometric_dialog_default_subtitle);
+                        break;
+                }
+                return result;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public CharSequence getSettingName(
+                int userId,
+                String opPackageName,
+                @Authenticators.Types int authenticators) throws RemoteException {
+
+            // Only allow internal clients to call getButtonLabel with a different userId.
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            if (userId != callingUserId) {
+                checkInternalPermission();
+            } else {
+                checkPermission();
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                @BiometricAuthenticator.Modality final int modality =
+                        mBiometricService.getSupportedModalities(authenticators);
+
+                final String result;
+                switch (modality) {
+                    // Handle the case of a single supported modality.
+                    case BiometricAuthenticator.TYPE_NONE:
+                        result = null;
+                        break;
+                    case BiometricAuthenticator.TYPE_CREDENTIAL:
+                        result = getContext().getString(R.string.screen_lock_app_setting_name);
+                        break;
+                    case BiometricAuthenticator.TYPE_IRIS:
+                        result = getContext().getString(R.string.biometric_app_setting_name);
+                        break;
+                    case BiometricAuthenticator.TYPE_FINGERPRINT:
+                        result = getContext().getString(R.string.fingerprint_app_setting_name);
+                        break;
+                    case BiometricAuthenticator.TYPE_FACE:
+                        result = getContext().getString(R.string.face_app_setting_name);
+                        break;
+
+                    // Handle other possible modality combinations.
+                    default:
+                        if ((modality & BiometricAuthenticator.TYPE_CREDENTIAL) == 0) {
+                            // 2+ biometric modalities are supported (but not device credential).
+                            result = getContext().getString(R.string.biometric_app_setting_name);
+                        } else {
+                            @BiometricAuthenticator.Modality final int biometricModality =
+                                    modality & ~BiometricAuthenticator.TYPE_CREDENTIAL;
+                            if (biometricModality == BiometricAuthenticator.TYPE_FINGERPRINT) {
+                                // Only device credential and fingerprint are supported.
+                                result = getContext().getString(
+                                        R.string.fingerprint_or_screen_lock_app_setting_name);
+                            } else if (biometricModality == BiometricAuthenticator.TYPE_FACE) {
+                                // Only device credential and face are supported.
+                                result = getContext().getString(
+                                        R.string.face_or_screen_lock_app_setting_name);
+                            } else {
+                                // Device credential and 1+ other biometric(s) are supported.
+                                result = getContext().getString(
+                                        R.string.biometric_or_screen_lock_app_setting_name);
+                            }
+                        }
+                        break;
+                }
+                return result;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     }
 
     public AuthService(Context context) {
@@ -442,4 +605,10 @@
         return mInjector.getAppOps(getContext()).noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid,
                 opPackageName, null /* attributionTag */, reason) == AppOpsManager.MODE_ALLOWED;
     }
+
+    @BiometricAuthenticator.Modality
+    private static int getCredentialBackupModality(@BiometricAuthenticator.Modality int modality) {
+        return modality == BiometricAuthenticator.TYPE_CREDENTIAL
+                ? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL);
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 00a4e43..a888209 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -666,14 +666,9 @@
                 throw new SecurityException("Invalid authenticator configuration");
             }
 
-            final PromptInfo promptInfo = new PromptInfo();
-            promptInfo.setAuthenticators(authenticators);
-
             try {
-                PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager,
-                        mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo,
-                        opPackageName,
-                        false /* checkDevicePolicyManager */);
+                final PreAuthInfo preAuthInfo =
+                        createPreAuthInfo(opPackageName, userId, authenticators);
                 return preAuthInfo.getCanAuthenticateResult();
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote exception", e);
@@ -807,6 +802,64 @@
             return Authenticators.EMPTY_SET;
         }
 
+        @Override // Binder call
+        public int getCurrentModality(
+                String opPackageName,
+                int userId,
+                int callingUserId,
+                @Authenticators.Types int authenticators) {
+
+            checkInternalPermission();
+
+            Slog.d(TAG, "getCurrentModality: User=" + userId
+                    + ", Caller=" + callingUserId
+                    + ", Authenticators=" + authenticators);
+
+            if (!Utils.isValidAuthenticatorConfig(authenticators)) {
+                throw new SecurityException("Invalid authenticator configuration");
+            }
+
+            try {
+                final PreAuthInfo preAuthInfo =
+                        createPreAuthInfo(opPackageName, userId, authenticators);
+                return preAuthInfo.getPreAuthenticateStatus().first;
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
+                return BiometricAuthenticator.TYPE_NONE;
+            }
+        }
+
+        @Override // Binder call
+        public int getSupportedModalities(@Authenticators.Types int authenticators) {
+            checkInternalPermission();
+
+            Slog.d(TAG, "getSupportedModalities: Authenticators=" + authenticators);
+
+            if (!Utils.isValidAuthenticatorConfig(authenticators)) {
+                throw new SecurityException("Invalid authenticator configuration");
+            }
+
+            @BiometricAuthenticator.Modality int modality =
+                    Utils.isCredentialRequested(authenticators)
+                            ? BiometricAuthenticator.TYPE_CREDENTIAL
+                            : BiometricAuthenticator.TYPE_NONE;
+
+            if (Utils.isBiometricRequested(authenticators)) {
+                @Authenticators.Types final int requestedStrength =
+                        Utils.getPublicBiometricStrength(authenticators);
+
+                // Add modalities of all biometric sensors that meet the authenticator requirements.
+                for (final BiometricSensor sensor : mSensors) {
+                    @Authenticators.Types final int sensorStrength = sensor.getCurrentStrength();
+                    if (Utils.isAtLeastStrength(sensorStrength, requestedStrength)) {
+                        modality |= sensor.modality;
+                    }
+                }
+            }
+
+            return modality;
+        }
+
         @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
@@ -845,6 +898,19 @@
                 "Must have USE_BIOMETRIC_INTERNAL permission");
     }
 
+    @NonNull
+    private PreAuthInfo createPreAuthInfo(
+            @NonNull String opPackageName,
+            int userId,
+            @Authenticators.Types int authenticators) throws RemoteException {
+
+        final PromptInfo promptInfo = new PromptInfo();
+        promptInfo.setAuthenticators(authenticators);
+
+        return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors,
+                userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */);
+    }
+
     /**
      * Class for injecting dependencies into BiometricService.
      * TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 5cd0bbf..d9e21a8 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -153,6 +153,16 @@
     /**
      * Checks if any of the publicly defined strengths are set.
      *
+     * @param authenticators composed of one or more values from {@link Authenticators}
+     * @return true if biometric authentication is allowed.
+     */
+    static boolean isBiometricRequested(@Authenticators.Types int authenticators) {
+        return getPublicBiometricStrength(authenticators) != 0;
+    }
+
+    /**
+     * Checks if any of the publicly defined strengths are set.
+     *
      * @param promptInfo should be first processed by
      * {@link #combineAuthenticatorBundles(PromptInfo)}
      * @return true if biometric authentication is allowed.
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 2de709e..088249e 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -52,6 +52,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -59,6 +60,7 @@
 import android.view.autofill.AutofillManagerInternal;
 import android.widget.Toast;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
@@ -163,6 +165,10 @@
     private static final boolean IS_EMULATOR =
         SystemProperties.getBoolean("ro.kernel.qemu", false);
 
+    // DeviceConfig properties
+    private static final String PROPERTY_SHOW_ACCESS_NOTIFICATIONS = "show_access_notifications";
+    private static final boolean DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
+
     private final ActivityManagerInternal mAmInternal;
     private final IUriGrantsManager mUgm;
     private final UriGrantsManagerInternal mUgmInternal;
@@ -176,8 +182,14 @@
     private HostClipboardMonitor mHostClipboardMonitor = null;
     private Thread mHostMonitorThread = null;
 
+    @GuardedBy("mLock")
     private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
 
+    @GuardedBy("mLock")
+    private boolean mShowAccessNotifications = DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
+
+    private final Object mLock = new Object();
+
     /**
      * Instantiates the clipboard.
      */
@@ -204,7 +216,7 @@
                             new ClipData("host clipboard",
                                          new String[]{"text/plain"},
                                          new ClipData.Item(contents));
-                        synchronized(mClipboards) {
+                        synchronized (mLock) {
                             setPrimaryClipInternal(getClipboard(0), clip,
                                     android.os.Process.SYSTEM_UID, null);
                         }
@@ -213,6 +225,10 @@
             mHostMonitorThread = new Thread(mHostClipboardMonitor);
             mHostMonitorThread.start();
         }
+
+        updateConfig();
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CLIPBOARD,
+                getContext().getMainExecutor(), properties -> updateConfig());
     }
 
     @Override
@@ -222,11 +238,18 @@
 
     @Override
     public void onUserStopped(@NonNull TargetUser user) {
-        synchronized (mClipboards) {
+        synchronized (mLock) {
             mClipboards.remove(user.getUserIdentifier());
         }
     }
 
+    private void updateConfig() {
+        synchronized (mLock) {
+            mShowAccessNotifications = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CLIPBOARD,
+                    PROPERTY_SHOW_ACCESS_NOTIFICATIONS, DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
+        }
+    }
+
     private class ListenerInfo {
         final int mUid;
         final String mPackageName;
@@ -472,7 +495,7 @@
     };
 
     private PerUserClipboard getClipboard(@UserIdInt int userId) {
-        synchronized (mClipboards) {
+        synchronized (mLock) {
             PerUserClipboard puc = mClipboards.get(userId);
             if (puc == null) {
                 puc = new PerUserClipboard(userId);
@@ -849,9 +872,10 @@
         if (clipboard.primaryClip == null) {
             return;
         }
-        if (Settings.Global.getInt(getContext().getContentResolver(),
-                "clipboard_access_toast_enabled", 1) == 0) {
-            return;
+        synchronized (mLock) {
+            if (!mShowAccessNotifications) {
+                return;
+            }
         }
         // Don't notify if the app accessing the clipboard is the same as the current owner.
         if (UserHandle.isSameApp(uid, clipboard.primaryClipUid)) {
@@ -880,8 +904,8 @@
         CharSequence sourceAppLabel = null;
         if (clipboard.mPrimaryClipPackage != null) {
             try {
-                sourceAppLabel = mPm.getApplicationLabel(
-                        mPm.getApplicationInfo(clipboard.mPrimaryClipPackage, 0));
+                sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
+                        clipboard.mPrimaryClipPackage, 0, userId));
             } catch (PackageManager.NameNotFoundException e) {
                 // leave label as null
             }
@@ -889,7 +913,7 @@
 
         try {
             CharSequence callingAppLabel = mPm.getApplicationLabel(
-                    mPm.getApplicationInfo(callingPackage, 0));
+                    mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
             String message;
             if (sourceAppLabel != null) {
                 message = callingAppLabel + " pasted from " + sourceAppLabel;
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index df83df9..5cf478a 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -80,6 +80,15 @@
     }
 
     /**
+     * @param change an object generated by services/core/xsd/platform-compat-config.xsd
+     */
+    public CompatChange(Change change) {
+        this(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
+                change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
+                change.getDescription(), change.getOverridable());
+    }
+
+    /**
      * @param changeId Unique ID for the change. See {@link android.compat.Compatibility}.
      * @param name Short descriptive name.
      * @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter};
@@ -93,15 +102,10 @@
             boolean overridable) {
         super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly,
               description, overridable);
-    }
 
-    /**
-     * @param change an object generated by services/core/xsd/platform-compat-config.xsd
-     */
-    public CompatChange(Change change) {
-        super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
-                change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
-                change.getDescription(), change.getOverridable());
+        // Initialize override maps.
+        mEvaluatedOverrides = new HashMap<>();
+        mRawOverrides = new HashMap<>();
     }
 
     void registerListener(ChangeListener listener) {
@@ -127,18 +131,13 @@
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
-        if (mEvaluatedOverrides == null) {
-            mEvaluatedOverrides = new HashMap<>();
-        }
         mEvaluatedOverrides.put(pname, enabled);
         notifyListener(pname);
     }
 
     private void removePackageOverrideInternal(String pname) {
-        if (mEvaluatedOverrides != null) {
-            if (mEvaluatedOverrides.remove(pname) != null) {
-                notifyListener(pname);
-            }
+        if (mEvaluatedOverrides.remove(pname) != null) {
+            notifyListener(pname);
         }
     }
 
@@ -157,9 +156,6 @@
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
-        if (mRawOverrides == null) {
-            mRawOverrides = new HashMap<>();
-        }
         mRawOverrides.put(packageName, override);
         recheckOverride(packageName, allowedState, context);
     }
@@ -212,7 +208,7 @@
     }
 
     boolean hasPackageOverride(String pname) {
-        return mRawOverrides != null && mRawOverrides.containsKey(pname);
+        return mRawOverrides.containsKey(pname);
     }
     /**
      * Remove any package override for the given package name, restoring the default behaviour.
@@ -223,7 +219,7 @@
      */
     boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
             Context context) {
-        if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) {
+        if (mRawOverrides.remove(pname) != null) {
             recheckOverride(pname, allowedState, context);
             return true;
         }
@@ -241,7 +237,7 @@
         if (app == null) {
             return defaultValue();
         }
-        if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) {
+        if (mEvaluatedOverrides.containsKey(app.packageName)) {
             return mEvaluatedOverrides.get(app.packageName);
         }
         if (getDisabled()) {
@@ -289,7 +285,7 @@
      * @return true if there is such override
      */
     private boolean hasOverride(String packageName) {
-        return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName);
+        return mEvaluatedOverrides.containsKey(packageName);
     }
 
     /**
@@ -298,20 +294,15 @@
      * @return true if there is such a deferred override
      */
     private boolean hasRawOverride(String packageName) {
-        return mRawOverrides != null && mRawOverrides.containsKey(packageName);
+        return mRawOverrides.containsKey(packageName);
+    }
+
+    void clearOverrides() {
+        mRawOverrides.clear();
+        mEvaluatedOverrides.clear();
     }
 
     void loadOverrides(ChangeOverrides changeOverrides) {
-        if (mRawOverrides == null) {
-            mRawOverrides = new HashMap<>();
-        }
-        mRawOverrides.clear();
-
-        if (mEvaluatedOverrides == null) {
-            mEvaluatedOverrides = new HashMap<>();
-        }
-        mEvaluatedOverrides.clear();
-
         // Load deferred overrides for backwards compatibility
         if (changeOverrides.getDeferred() != null) {
             for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
@@ -345,34 +336,30 @@
     }
 
     ChangeOverrides saveOverrides() {
-        if (mRawOverrides == null || mRawOverrides.isEmpty()) {
+        if (mRawOverrides.isEmpty()) {
             return null;
         }
         ChangeOverrides changeOverrides = new ChangeOverrides();
         changeOverrides.setChangeId(getId());
         ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw();
         List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue();
-        if (mRawOverrides != null) {
-            for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
-                RawOverrideValue override = new RawOverrideValue();
-                override.setPackageName(entry.getKey());
-                override.setMinVersionCode(entry.getValue().getMinVersionCode());
-                override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
-                override.setEnabled(entry.getValue().getEnabled());
-                rawList.add(override);
-            }
+        for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
+            RawOverrideValue override = new RawOverrideValue();
+            override.setPackageName(entry.getKey());
+            override.setMinVersionCode(entry.getValue().getMinVersionCode());
+            override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
+            override.setEnabled(entry.getValue().getEnabled());
+            rawList.add(override);
         }
         changeOverrides.setRaw(rawOverrides);
 
         ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
         List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
-        if (mEvaluatedOverrides != null) {
-            for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
-                OverrideValue override = new OverrideValue();
-                override.setPackageName(entry.getKey());
-                override.setEnabled(entry.getValue());
-                validatedList.add(override);
-            }
+        for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
+            OverrideValue override = new OverrideValue();
+            override.setPackageName(entry.getKey());
+            override.setEnabled(entry.getValue());
+            validatedList.add(override);
         }
         changeOverrides.setValidated(validatedOverrides);
         return changeOverrides;
@@ -394,10 +381,10 @@
         if (getLoggingOnly()) {
             sb.append("; loggingOnly");
         }
-        if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) {
+        if (!mEvaluatedOverrides.isEmpty()) {
             sb.append("; packageOverrides=").append(mEvaluatedOverrides);
         }
-        if (mRawOverrides != null && mRawOverrides.size() > 0) {
+        if (!mRawOverrides.isEmpty()) {
             sb.append("; rawOverrides=").append(mRawOverrides);
         }
         if (getOverridable()) {
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 66a6520..2c053b4 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -67,6 +67,7 @@
 
     private static final String TAG = "CompatConfig";
     private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
+    private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat";
     private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
 
     @GuardedBy("mChanges")
@@ -94,8 +95,7 @@
             config.initConfigFromLib(Environment.buildPath(
                     apex.apexDirectory, "etc", "compatconfig"));
         }
-        File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE);
-        config.initOverrides(overridesFile);
+        config.initOverrides();
         config.invalidateCache();
         return config;
     }
@@ -525,10 +525,34 @@
         }
     }
 
-    void initOverrides(File overridesFile) {
+    private void initOverrides() {
+        initOverrides(new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE),
+                new File(STATIC_OVERRIDES_PRODUCT_DIR, OVERRIDES_FILE));
+    }
+
+    @VisibleForTesting
+    void initOverrides(File dynamicOverridesFile, File staticOverridesFile) {
+        // Clear overrides from all changes before loading.
+        synchronized (mChanges) {
+            for (int i = 0; i < mChanges.size(); ++i) {
+                mChanges.valueAt(i).clearOverrides();
+            }
+        }
+
+        loadOverrides(staticOverridesFile);
+
+        mOverridesFile = dynamicOverridesFile;
+        loadOverrides(dynamicOverridesFile);
+
+        if (staticOverridesFile.exists()) {
+            // Only save overrides if there is a static overrides file.
+            saveOverrides();
+        }
+    }
+
+    private void loadOverrides(File overridesFile) {
         if (!overridesFile.exists()) {
-            mOverridesFile = overridesFile;
-            // There have not been any overrides added yet.
+            // Overrides file doesn't exist.
             return;
         }
 
@@ -548,7 +572,6 @@
             Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString());
             return;
         }
-        mOverridesFile = overridesFile;
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index fbd089c..15f43a0 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -52,6 +52,7 @@
     private SignalStrength mSignalStrength;
     private ServiceState mServiceState;
     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    private int mNrState = NetworkRegistrationInfo.NR_STATE_NONE;
 
     public DataConnectionStats(Context context, Handler listenerHandler) {
         mContext = context;
@@ -99,7 +100,7 @@
                 : regInfo.getAccessNetworkTechnology();
         // If the device is in NSA NR connection the networkType will report as LTE.
         // For cell dwell rate metrics, this should report NR instead.
-        if (regInfo != null && regInfo.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
+        if (mNrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
             networkType = TelephonyManager.NETWORK_TYPE_NR;
         }
         if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
@@ -171,6 +172,7 @@
         @Override
         public void onServiceStateChanged(ServiceState state) {
             mServiceState = state;
+            mNrState = state.getNrState();
             notePhoneDataConnectionState();
         }
 
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 43d9ade..4f6b530 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -19,6 +19,8 @@
 import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
@@ -147,17 +149,18 @@
     }
 
     public static class PrivateDnsValidationUpdate {
-        final public int netId;
-        final public InetAddress ipAddress;
-        final public String hostname;
-        final public boolean validated;
+        public final int netId;
+        public final InetAddress ipAddress;
+        public final String hostname;
+        // Refer to IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_*.
+        public final int validationResult;
 
         public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
-                String hostname, boolean validated) {
+                String hostname, int validationResult) {
             this.netId = netId;
             this.ipAddress = ipAddress;
             this.hostname = hostname;
-            this.validated = validated;
+            this.validationResult = validationResult;
         }
     }
 
@@ -216,10 +219,13 @@
             if (!mValidationMap.containsKey(p)) {
                 return;
             }
-            if (update.validated) {
+            if (update.validationResult == VALIDATION_RESULT_SUCCESS) {
                 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
-            } else {
+            } else if (update.validationResult == VALIDATION_RESULT_FAILURE) {
                 mValidationMap.put(p, ValidationStatus.FAILED);
+            } else {
+                Log.e(TAG, "Unknown private dns validation operation="
+                        + update.validationResult);
             }
         }
 
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 34d9ccc..7b20ded 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -57,8 +57,8 @@
 import android.util.Pair;
 
 import com.android.internal.R;
-import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.HexDump;
 import com.android.net.module.util.IpUtils;
 
 import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 641287f..fa80b25 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -29,14 +29,12 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.RouteInfo;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetworkStackConstants;
-import com.android.server.net.BaseNetworkObserver;
 
 import java.net.Inet6Address;
 import java.util.Objects;
@@ -48,7 +46,7 @@
  *
  * @hide
  */
-public class Nat464Xlat extends BaseNetworkObserver {
+public class Nat464Xlat {
     private static final String TAG = Nat464Xlat.class.getSimpleName();
 
     // This must match the interface prefix in clatd.c.
@@ -70,7 +68,6 @@
 
     private final IDnsResolver mDnsResolver;
     private final INetd mNetd;
-    private final INetworkManagementService mNMService;
 
     // The network we're running on, and its type.
     private final NetworkAgentInfo mNetwork;
@@ -99,11 +96,9 @@
 
     private boolean mPrefixDiscoveryRunning;
 
-    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
-            INetworkManagementService nmService) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver) {
         mDnsResolver = dnsResolver;
         mNetd = netd;
-        mNMService = nmService;
         mNetwork = nai;
     }
 
@@ -174,13 +169,6 @@
      * and set internal state.
      */
     private void enterStartingState(String baseIface) {
-        try {
-            mNMService.registerObserver(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
-            return;
-        }
-
         mNat64PrefixInUse = selectNat64Prefix();
         String addrStr = null;
         try {
@@ -216,11 +204,6 @@
      * Unregister as a base observer for the stacked interface, and clear internal state.
      */
     private void leaveStartedState() {
-        try {
-            mNMService.unregisterObserver(this);
-        } catch (RemoteException | IllegalStateException e) {
-            Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
-        }
         mNat64PrefixInUse = null;
         mIface = null;
         mBaseIface = null;
@@ -507,12 +490,10 @@
         stop();
     }
 
-    @Override
     public void interfaceLinkStateChanged(String iface, boolean up) {
         mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
     }
 
-    @Override
     public void interfaceRemoved(String iface) {
         mNetwork.handler().post(() -> handleInterfaceRemoved(iface));
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4cf5274..cac6cab 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -43,7 +43,6 @@
 import android.net.TcpKeepalivePacketData;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.telephony.data.EpsBearerQosSessionAttributes;
@@ -341,8 +340,8 @@
     public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
             @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
-            IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
-            int creatorUid, QosCallbackTracker qosCallbackTracker) {
+            IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
+            QosCallbackTracker qosCallbackTracker) {
         Objects.requireNonNull(net);
         Objects.requireNonNull(info);
         Objects.requireNonNull(lp);
@@ -356,7 +355,7 @@
         linkProperties = lp;
         networkCapabilities = nc;
         mScore = score;
-        clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
+        clatd = new Nat464Xlat(this, netd, dnsResolver);
         mConnService = connService;
         mContext = context;
         mHandler = handler;
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
index 816bf2b..0f5400d 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -27,7 +27,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.util.Slog;
+import android.util.Log;
 
 import java.util.Objects;
 
@@ -175,18 +175,14 @@
     }
 
     private static void log(@NonNull final String msg) {
-        Slog.d(TAG, msg);
+        Log.d(TAG, msg);
     }
 
     private static void logw(@NonNull final String msg) {
-        Slog.w(TAG, msg);
+        Log.w(TAG, msg);
     }
 
     private static void loge(@NonNull final String msg, final Throwable t) {
-        Slog.e(TAG, msg, t);
-    }
-
-    private static void logwtf(@NonNull final String msg) {
-        Slog.wtf(TAG, msg);
+        Log.e(TAG, msg, t);
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 7ef315c..8bda532 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -29,7 +29,7 @@
 import android.telephony.data.EpsBearerQosSessionAttributes;
 import android.util.Log;
 
-import com.android.internal.util.CollectionUtils;
+import com.android.net.module.util.CollectionUtils;
 import com.android.server.ConnectivityService;
 
 import java.util.ArrayList;
@@ -156,12 +156,13 @@
 
     private void handleUnregisterCallback(@NonNull final IBinder binder,
             final boolean sendToNetworkAgent) {
-        final QosCallbackAgentConnection agentConnection =
-                CollectionUtils.find(mConnections, c -> c.getBinder().equals(binder));
-        if (agentConnection == null) {
-            logw("handleUnregisterCallback: agentConnection is null");
+        final int connIndex =
+                CollectionUtils.indexOf(mConnections, c -> c.getBinder().equals(binder));
+        if (connIndex < 0) {
+            logw("handleUnregisterCallback: no matching agentConnection");
             return;
         }
+        final QosCallbackAgentConnection agentConnection = mConnections.get(connIndex);
 
         if (DBG) {
             log("handleUnregisterCallback: unregister "
@@ -226,10 +227,10 @@
      * @param network the network that was released
      */
     public void handleNetworkReleased(@Nullable final Network network) {
-        final List<QosCallbackAgentConnection> connections =
-                CollectionUtils.filter(mConnections, ac -> ac.getNetwork().equals(network));
-
-        for (final QosCallbackAgentConnection agentConnection : connections) {
+        // Iterate in reverse order as agent connections will be removed when unregistering
+        for (int i = mConnections.size() - 1; i >= 0; i--) {
+            final QosCallbackAgentConnection agentConnection = mConnections.get(i);
+            if (!agentConnection.getNetwork().equals(network)) continue;
             agentConnection.sendEventQosCallbackError(
                     QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
 
@@ -247,15 +248,14 @@
             @NonNull final String logPrefix,
             @NonNull final AgentConnectionAction action) {
         mConnectivityServiceHandler.post(() -> {
-            final QosCallbackAgentConnection ac =
-                    CollectionUtils.find(mConnections,
+            final int acIndex = CollectionUtils.indexOf(mConnections,
                             c -> c.getAgentCallbackId() == qosCallbackId);
-            if (ac == null) {
+            if (acIndex == -1) {
                 loge(logPrefix + ": " + qosCallbackId + " missing callback id");
                 return;
             }
 
-            action.execute(ac);
+            action.execute(mConnections.get(acIndex));
         });
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 01ac81fb..2e61ae1 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,6 +22,7 @@
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+import static android.os.PowerWhitelistManager.REASON_VPN;
 
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
@@ -100,7 +101,12 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.KeyStore;
+import android.security.KeyStore2;
+import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.keystore.KeyProperties;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyPermission;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -131,6 +137,12 @@
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -156,6 +168,7 @@
     private static final String TAG = "Vpn";
     private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
     private static final boolean LOGD = true;
+    private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
 
     // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
     // the device idle allowlist during service launch and VPN bootstrap.
@@ -215,6 +228,13 @@
     private final Ikev2SessionCreator mIkev2SessionCreator;
     private final UserManager mUserManager;
 
+    private final VpnProfileStore mVpnProfileStore;
+
+    @VisibleForTesting
+    VpnProfileStore getVpnProfileStore() {
+        return mVpnProfileStore;
+    }
+
     /**
      * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
      * only applies to {@link VpnService} connections.
@@ -392,24 +412,25 @@
     }
 
     public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
-            @UserIdInt int userId, @NonNull KeyStore keyStore) {
-        this(looper, context, new Dependencies(), netService, netd, userId, keyStore,
+            @UserIdInt int userId, VpnProfileStore vpnProfileStore) {
+        this(looper, context, new Dependencies(), netService, netd, userId, vpnProfileStore,
                 new SystemServices(context), new Ikev2SessionCreator());
     }
 
     @VisibleForTesting
     public Vpn(Looper looper, Context context, Dependencies deps,
             INetworkManagementService netService, INetd netd, @UserIdInt int userId,
-            @NonNull KeyStore keyStore) {
-        this(looper, context, deps, netService, netd, userId, keyStore,
+            VpnProfileStore vpnProfileStore) {
+        this(looper, context, deps, netService, netd, userId, vpnProfileStore,
                 new SystemServices(context), new Ikev2SessionCreator());
     }
 
     @VisibleForTesting
     protected Vpn(Looper looper, Context context, Dependencies deps,
             INetworkManagementService netService, INetd netd,
-            int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
+            int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices,
             Ikev2SessionCreator ikev2SessionCreator) {
+        mVpnProfileStore = vpnProfileStore;
         mContext = context;
         mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
         mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
@@ -445,7 +466,7 @@
         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
         mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
 
-        loadAlwaysOnPackage(keyStore);
+        loadAlwaysOnPackage();
     }
 
     /**
@@ -566,11 +587,9 @@
      * </ul>
      *
      * @param packageName the canonical package name of the VPN app
-     * @param keyStore the keystore instance to use for checking if the app has a Platform VPN
-     *     profile installed.
      * @return {@code true} if and only if the VPN app exists and supports always-on mode
      */
-    public boolean isAlwaysOnPackageSupported(String packageName, @NonNull KeyStore keyStore) {
+    public boolean isAlwaysOnPackageSupported(String packageName) {
         enforceSettingsPermission();
 
         if (packageName == null) {
@@ -579,7 +598,7 @@
 
         final long oldId = Binder.clearCallingIdentity();
         try {
-            if (getVpnProfilePrivileged(packageName, keyStore) != null) {
+            if (getVpnProfilePrivileged(packageName) != null) {
                 return true;
             }
         } finally {
@@ -631,17 +650,15 @@
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
      * @param lockdownAllowlist packages to be allowed from lockdown.
-     * @param keyStore the Keystore instance to use for checking of PlatformVpnProfile(s)
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     public synchronized boolean setAlwaysOnPackage(
             @Nullable String packageName,
             boolean lockdown,
-            @Nullable List<String> lockdownAllowlist,
-            @NonNull KeyStore keyStore) {
+            @Nullable List<String> lockdownAllowlist) {
         enforceControlPermissionOrInternalCaller();
 
-        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist, keyStore)) {
+        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
             saveAlwaysOnPackage();
             return true;
         }
@@ -658,13 +675,12 @@
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
      * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if
      *     {@code lockdown} is {@code true}. Packages must not contain commas.
-     * @param keyStore the system keystore instance to check for profiles
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     @GuardedBy("this")
     private boolean setAlwaysOnPackageInternal(
             @Nullable String packageName, boolean lockdown,
-            @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) {
+            @Nullable List<String> lockdownAllowlist) {
         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
             return false;
@@ -683,7 +699,7 @@
             final VpnProfile profile;
             final long oldId = Binder.clearCallingIdentity();
             try {
-                profile = getVpnProfilePrivileged(packageName, keyStore);
+                profile = getVpnProfilePrivileged(packageName);
             } finally {
                 Binder.restoreCallingIdentity(oldId);
             }
@@ -758,7 +774,7 @@
 
     /** Load the always-on package and lockdown config from Settings. */
     @GuardedBy("this")
-    private void loadAlwaysOnPackage(@NonNull KeyStore keyStore) {
+    private void loadAlwaysOnPackage() {
         final long token = Binder.clearCallingIdentity();
         try {
             final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
@@ -770,7 +786,7 @@
             final List<String> allowedPackages = TextUtils.isEmpty(allowlistString)
                     ? Collections.emptyList() : Arrays.asList(allowlistString.split(","));
             setAlwaysOnPackageInternal(
-                    alwaysOnPackage, alwaysOnLockdown, allowedPackages, keyStore);
+                    alwaysOnPackage, alwaysOnLockdown, allowedPackages);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -779,11 +795,10 @@
     /**
      * Starts the currently selected always-on VPN
      *
-     * @param keyStore the keyStore instance for looking up PlatformVpnProfile(s)
      * @return {@code true} if the service was started, the service was already connected, or there
      *     was no always-on VPN to start. {@code false} otherwise.
      */
-    public boolean startAlwaysOnVpn(@NonNull KeyStore keyStore) {
+    public boolean startAlwaysOnVpn() {
         final String alwaysOnPackage;
         synchronized (this) {
             alwaysOnPackage = getAlwaysOnPackage();
@@ -792,8 +807,8 @@
                 return true;
             }
             // Remove always-on VPN if it's not supported.
-            if (!isAlwaysOnPackageSupported(alwaysOnPackage, keyStore)) {
-                setAlwaysOnPackage(null, false, null, keyStore);
+            if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
+                setAlwaysOnPackage(null, false, null);
                 return false;
             }
             // Skip if the service is already established. This isn't bulletproof: it's not bound
@@ -807,10 +822,9 @@
         final long oldId = Binder.clearCallingIdentity();
         try {
             // Prefer VPN profiles, if any exist.
-            VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage, keyStore);
+            VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage);
             if (profile != null) {
-                startVpnProfilePrivileged(profile, alwaysOnPackage,
-                        null /* keyStore for private key retrieval - unneeded */);
+                startVpnProfilePrivileged(profile, alwaysOnPackage);
 
                 // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was
                 // correctly parsed, and the VPN has started running in a different thread. The only
@@ -825,7 +839,8 @@
             // a short time, so we can bootstrap the VPN service.
             DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
-                    VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, "vpn");
+                    VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN,
+                    "vpn");
 
             // Start the VPN service declared in the app's manifest.
             Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
@@ -2011,27 +2026,83 @@
      * secondary thread to perform connection work, returning quickly.
      *
      * Should only be called to respond to Binder requests as this enforces caller permission. Use
-     * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, Network, LinkProperties)} to skip the
+     * {@link #startLegacyVpnPrivileged(VpnProfile, Network, LinkProperties)} to skip the
      * permission check only when the caller is trusted (or the call is initiated by the system).
      */
-    public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, @Nullable Network underlying,
+    public void startLegacyVpn(VpnProfile profile, @Nullable Network underlying,
             LinkProperties egress) {
         enforceControlPermission();
         final long token = Binder.clearCallingIdentity();
         try {
-            startLegacyVpnPrivileged(profile, keyStore, underlying, egress);
+            startLegacyVpnPrivileged(profile, underlying, egress);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
+    private String makeKeystoreEngineGrantString(String alias) {
+        if (alias == null) {
+            return null;
+        }
+        // If Keystore 2.0 is not enabled the legacy private key prefix is used.
+        if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
+            return Credentials.USER_PRIVATE_KEY + alias;
+        }
+        final KeyStore2 keystore2 = KeyStore2.getInstance();
+
+        KeyDescriptor key = new KeyDescriptor();
+        key.domain = Domain.APP;
+        key.nspace = KeyProperties.NAMESPACE_APPLICATION;
+        key.alias = alias;
+        key.blob = null;
+
+        final int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO;
+
+        try {
+            // The native vpn daemon is running as VPN_UID. This tells Keystore 2.0
+            // to allow a process running with this UID to access the key designated by
+            // the KeyDescriptor `key`. `grant` returns a new KeyDescriptor with a grant
+            // identifier. This identifier needs to be communicated to the vpn daemon.
+            key = keystore2.grant(key, android.os.Process.VPN_UID, grantAccessVector);
+        } catch (android.security.KeyStoreException e) {
+            Log.e(TAG, "Failed to get grant for keystore key.", e);
+            throw new IllegalStateException("Failed to get grant for keystore key.", e);
+        }
+
+        // Turn the grant identifier into a string as understood by the keystore boringssl engine
+        // in system/security/keystore-engine.
+        return KeyStore2.makeKeystoreEngineGrantString(key.nspace);
+    }
+
+    private String getCaCertificateFromKeystoreAsPem(@NonNull KeyStore keystore,
+            @NonNull String alias)
+            throws KeyStoreException, IOException, CertificateEncodingException {
+        if (keystore.isCertificateEntry(alias)) {
+            final Certificate cert = keystore.getCertificate(alias);
+            if (cert == null) return null;
+            return new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
+        } else {
+            final Certificate[] certs = keystore.getCertificateChain(alias);
+            // If there is none or one entry it means there is no CA entry associated with this
+            // alias.
+            if (certs == null || certs.length <= 1) {
+                return null;
+            }
+            // If this is not a (pure) certificate entry, then there is a user certificate which
+            // will be included at the beginning of the certificate chain. But the caller of this
+            // function does not expect this certificate to be included, so we cut it off.
+            return new String(Credentials.convertToPem(
+                    Arrays.copyOfRange(certs, 1, certs.length)), StandardCharsets.UTF_8);
+        }
+    }
+
     /**
-     * Like {@link #startLegacyVpn(VpnProfile, KeyStore, Network, LinkProperties)}, but does not
+     * Like {@link #startLegacyVpn(VpnProfile, Network, LinkProperties)}, but does not
      * check permissions under the assumption that the caller is the system.
      *
      * Callers are responsible for checking permissions if needed.
      */
-    public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
+    public void startLegacyVpnPrivileged(VpnProfile profile,
             @Nullable Network underlying, @NonNull LinkProperties egress) {
         UserInfo user = mUserManager.getUserInfo(mUserId);
         if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
@@ -2048,18 +2119,27 @@
         String userCert = "";
         String caCert = "";
         String serverCert = "";
-        if (!profile.ipsecUserCert.isEmpty()) {
-            privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
-            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
-            userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
-        }
-        if (!profile.ipsecCaCert.isEmpty()) {
-            byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
-            caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
-        }
-        if (!profile.ipsecServerCert.isEmpty()) {
-            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
-            serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
+
+        try {
+            final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER);
+            keystore.load(null);
+            if (!profile.ipsecUserCert.isEmpty()) {
+                privateKey = profile.ipsecUserCert;
+                final Certificate cert = keystore.getCertificate(profile.ipsecUserCert);
+                userCert = (cert == null) ? null
+                         : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
+            }
+            if (!profile.ipsecCaCert.isEmpty()) {
+                caCert = getCaCertificateFromKeystoreAsPem(keystore, profile.ipsecCaCert);
+            }
+            if (!profile.ipsecServerCert.isEmpty()) {
+                final Certificate cert = keystore.getCertificate(profile.ipsecServerCert);
+                serverCert = (cert == null) ? null
+                        : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
+            }
+        } catch (CertificateException | KeyStoreException | IOException
+                | NoSuchAlgorithmException e) {
+            throw new IllegalStateException("Failed to load credentials from AndroidKeyStore", e);
         }
         if (userCert == null || caCert == null || serverCert == null) {
             throw new IllegalStateException("Cannot load credentials");
@@ -2080,7 +2160,7 @@
 
                 // Start VPN profile
                 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
-                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore);
+                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
                 return;
             case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
                 // Ikev2VpnProfiles expect a base64-encoded preshared key.
@@ -2089,7 +2169,7 @@
 
                 // Start VPN profile
                 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
-                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore);
+                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
                 return;
             case VpnProfile.TYPE_L2TP_IPSEC_PSK:
                 racoon = new String[] {
@@ -2099,8 +2179,8 @@
                 break;
             case VpnProfile.TYPE_L2TP_IPSEC_RSA:
                 racoon = new String[] {
-                    iface, profile.server, "udprsa", privateKey, userCert,
-                    caCert, serverCert, "1701",
+                    iface, profile.server, "udprsa", makeKeystoreEngineGrantString(privateKey),
+                    userCert, caCert, serverCert, "1701",
                 };
                 break;
             case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
@@ -2111,8 +2191,8 @@
                 break;
             case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
                 racoon = new String[] {
-                    iface, profile.server, "xauthrsa", privateKey, userCert,
-                    caCert, serverCert, profile.username, profile.password, "", gateway,
+                    iface, profile.server, "xauthrsa", makeKeystoreEngineGrantString(privateKey),
+                    userCert, caCert, serverCert, profile.username, profile.password, "", gateway,
                 };
                 break;
             case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
@@ -3047,14 +3127,12 @@
      *
      * @param packageName the package name of the app provisioning this profile
      * @param profile the profile to be stored and provisioned
-     * @param keyStore the System keystore instance to save VPN profiles
      * @returns whether or not the app has already been granted user consent
      */
     public synchronized boolean provisionVpnProfile(
-            @NonNull String packageName, @NonNull VpnProfile profile, @NonNull KeyStore keyStore) {
+            @NonNull String packageName, @NonNull VpnProfile profile) {
         checkNotNull(packageName, "No package name provided");
         checkNotNull(profile, "No profile provided");
-        checkNotNull(keyStore, "KeyStore missing");
 
         verifyCallingUidAndPackage(packageName);
         enforceNotRestrictedUser();
@@ -3073,11 +3151,9 @@
         // Permissions checked during startVpnProfile()
         Binder.withCleanCallingIdentity(
                 () -> {
-                    keyStore.put(
+                    getVpnProfileStore().put(
                             getProfileNameForPackage(packageName),
-                            encodedProfile,
-                            Process.SYSTEM_UID,
-                            0 /* flags */);
+                            encodedProfile);
                 });
 
         // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop.
@@ -3095,12 +3171,10 @@
      * Deletes an app-provisioned VPN profile.
      *
      * @param packageName the package name of the app provisioning this profile
-     * @param keyStore the System keystore instance to save VPN profiles
      */
     public synchronized void deleteVpnProfile(
-            @NonNull String packageName, @NonNull KeyStore keyStore) {
+            @NonNull String packageName) {
         checkNotNull(packageName, "No package name provided");
-        checkNotNull(keyStore, "KeyStore missing");
 
         verifyCallingUidAndPackage(packageName);
         enforceNotRestrictedUser();
@@ -3112,13 +3186,13 @@
                     if (isCurrentIkev2VpnLocked(packageName)) {
                         if (mAlwaysOn) {
                             // Will transitively call prepareInternal(VpnConfig.LEGACY_VPN).
-                            setAlwaysOnPackage(null, false, null, keyStore);
+                            setAlwaysOnPackage(null, false, null);
                         } else {
                             prepareInternal(VpnConfig.LEGACY_VPN);
                         }
                     }
 
-                    keyStore.delete(getProfileNameForPackage(packageName), Process.SYSTEM_UID);
+                    getVpnProfileStore().remove(getProfileNameForPackage(packageName));
                 });
     }
 
@@ -3130,13 +3204,13 @@
      */
     @VisibleForTesting
     @Nullable
-    VpnProfile getVpnProfilePrivileged(@NonNull String packageName, @NonNull KeyStore keyStore) {
+    VpnProfile getVpnProfilePrivileged(@NonNull String packageName) {
         if (!mDeps.isCallerSystem()) {
             Log.wtf(TAG, "getVpnProfilePrivileged called as non-System UID ");
             return null;
         }
 
-        final byte[] encoded = keyStore.get(getProfileNameForPackage(packageName));
+        final byte[] encoded = getVpnProfileStore().get(getProfileNameForPackage(packageName));
         if (encoded == null) return null;
 
         return VpnProfile.decode("" /* Key unused */, encoded);
@@ -3150,12 +3224,10 @@
      * will not match during appop checks.
      *
      * @param packageName the package name of the app provisioning this profile
-     * @param keyStore the System keystore instance to retrieve VPN profiles
      */
     public synchronized void startVpnProfile(
-            @NonNull String packageName, @NonNull KeyStore keyStore) {
+            @NonNull String packageName) {
         checkNotNull(packageName, "No package name provided");
-        checkNotNull(keyStore, "KeyStore missing");
 
         enforceNotRestrictedUser();
 
@@ -3166,18 +3238,17 @@
 
         Binder.withCleanCallingIdentity(
                 () -> {
-                    final VpnProfile profile = getVpnProfilePrivileged(packageName, keyStore);
+                    final VpnProfile profile = getVpnProfilePrivileged(packageName);
                     if (profile == null) {
                         throw new IllegalArgumentException("No profile found for " + packageName);
                     }
 
-                    startVpnProfilePrivileged(profile, packageName,
-                            null /* keyStore for private key retrieval - unneeded */);
+                    startVpnProfilePrivileged(profile, packageName);
                 });
     }
 
     private synchronized void startVpnProfilePrivileged(
-            @NonNull VpnProfile profile, @NonNull String packageName, @Nullable KeyStore keyStore) {
+            @NonNull VpnProfile profile, @NonNull String packageName) {
         // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(),
         // by the Setting app via startLegacyVpn(), or by ConnectivityService via
         // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the
@@ -3208,7 +3279,7 @@
                 case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
                 case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
                     mVpnRunner =
-                            new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile, keyStore));
+                            new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile));
                     mVpnRunner.start();
                     break;
                 default:
@@ -3216,7 +3287,7 @@
                     Log.d(TAG, "Unknown VPN profile type: " + profile.type);
                     break;
             }
-        } catch (IOException | GeneralSecurityException e) {
+        } catch (GeneralSecurityException e) {
             // Reset mConfig
             mConfig = null;
 
diff --git a/services/core/java/com/android/server/connectivity/VpnProfileStore.java b/services/core/java/com/android/server/connectivity/VpnProfileStore.java
new file mode 100644
index 0000000..2f8aebf
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/VpnProfileStore.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.security.LegacyVpnProfileStore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Mockable indirection to the actual profile store.
+ * @hide
+ */
+public class VpnProfileStore {
+    /**
+     * Stores the profile under the alias in the profile database. Existing profiles by the
+     * same name will be replaced.
+     * @param alias The name of the profile
+     * @param profile The profile.
+     * @return true if the profile was successfully added. False otherwise.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean put(@NonNull String alias, @NonNull byte[] profile) {
+        return LegacyVpnProfileStore.put(alias, profile);
+    }
+
+    /**
+     * Retrieves a profile by the name alias from the profile database.
+     * @param alias Name of the profile to retrieve.
+     * @return The unstructured blob, that is the profile that was stored using
+     *         LegacyVpnProfileStore#put or with
+     *         android.security.Keystore.put(Credentials.VPN + alias).
+     *         Returns null if no profile was found.
+     * @hide
+     */
+    @VisibleForTesting
+    public byte[] get(@NonNull String alias) {
+        return LegacyVpnProfileStore.get(alias);
+    }
+
+    /**
+     * Removes a profile by the name alias from the profile database.
+     * @param alias Name of the profile to be removed.
+     * @return True if a profile was removed. False if no such profile was found.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean remove(@NonNull String alias) {
+        return LegacyVpnProfileStore.remove(alias);
+    }
+
+    /**
+     * Lists the vpn profiles stored in the database.
+     * @return An array of strings representing the aliases stored in the profile database.
+     *         The return value may be empty but never null.
+     * @hide
+     */
+    @VisibleForTesting
+    public @NonNull String[] list(@NonNull String prefix) {
+        return LegacyVpnProfileStore.list(prefix);
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 7b9ca37..ae0e001 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.content;
 
+import static android.os.PowerWhitelistManager.REASON_SYNC_MANAGER;
+
 import static com.android.server.content.SyncLogger.logSafe;
 
 import android.accounts.Account;
@@ -1671,7 +1673,7 @@
                         syncOperation.owningPackage,
                         mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
                         UserHandle.getUserId(syncOperation.owningUid),
-                        /* sync=*/ false, "sync by top app");
+                        /* sync=*/ false, REASON_SYNC_MANAGER, "sync by top app");
             }
         }
 
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index b3a6f26..658d27f 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -25,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.IDeviceStateManager;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
@@ -47,6 +48,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Optional;
 
 /**
@@ -76,6 +78,9 @@
 public final class DeviceStateManagerService extends SystemService {
     private static final String TAG = "DeviceStateManagerService";
     private static final boolean DEBUG = false;
+    // The device state to use as a placeholder before callback from the DeviceStateProvider occurs.
+    private static final DeviceState UNSPECIFIED_DEVICE_STATE =
+            new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED");
 
     private final Object mLock = new Object();
     @NonNull
@@ -87,11 +92,11 @@
     @GuardedBy("mLock")
     private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
 
-    // The current committed device state. The default of UNSET will be replaced by
-    // the current state after the initial callback from the DeviceStateProvider.
+    // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced
+    // by the current state after the initial callback from the DeviceStateProvider.
     @GuardedBy("mLock")
     @NonNull
-    private DeviceState mCommittedState = new DeviceState(MINIMUM_DEVICE_STATE, "UNSET");
+    private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE;
     // The device state that is currently awaiting callback from the policy to be committed.
     @GuardedBy("mLock")
     @NonNull
@@ -103,7 +108,7 @@
     // The device state that is set by the device state provider.
     @GuardedBy("mLock")
     @NonNull
-    private Optional<DeviceState> mBaseState = Optional.empty();
+    private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE;
 
     // List of processes registered to receive notifications about changes to device state and
     // request status indexed by process id.
@@ -166,7 +171,7 @@
      * @see #getOverrideState()
      */
     @NonNull
-    Optional<DeviceState> getBaseState() {
+    DeviceState getBaseState() {
         synchronized (mLock) {
             return mBaseState;
         }
@@ -203,33 +208,47 @@
     /** Returns the list of currently supported device state identifiers. */
     private int[] getSupportedStateIdentifiers() {
         synchronized (mLock) {
-            int[] supportedStates = new int[mDeviceStates.size()];
-            for (int i = 0; i < supportedStates.length; i++) {
-                supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
-            }
-            return supportedStates;
+            return getSupportedStateIdentifiersLocked();
         }
     }
 
+    /** Returns the list of currently supported device state identifiers. */
+    private int[] getSupportedStateIdentifiersLocked() {
+        int[] supportedStates = new int[mDeviceStates.size()];
+        for (int i = 0; i < supportedStates.length; i++) {
+            supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
+        }
+        return supportedStates;
+    }
+
+    @NonNull
+    private DeviceStateInfo getDeviceStateInfoLocked() {
+        final int[] supportedStates = getSupportedStateIdentifiersLocked();
+        final int baseState = mBaseState.getIdentifier();
+        final int currentState = mCommittedState.getIdentifier();
+
+        return new DeviceStateInfo(supportedStates, baseState, currentState);
+    }
+
     @VisibleForTesting
     IDeviceStateManager getBinderService() {
         return mBinderService;
     }
 
     private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
+        boolean updatedPendingState;
         synchronized (mLock) {
+            final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
+
             mDeviceStates.clear();
             for (int i = 0; i < supportedDeviceStates.length; i++) {
                 DeviceState state = supportedDeviceStates[i];
                 mDeviceStates.put(state.getIdentifier(), state);
             }
 
-            if (mBaseState.isPresent()
-                    && !isSupportedStateLocked(mBaseState.get().getIdentifier())) {
-                // The current base state is no longer valid. We'll clear it here, though
-                // we won't actually update the current state until a callback comes from the
-                // provider with the most recent state.
-                mBaseState = Optional.empty();
+            final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked();
+            if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) {
+                return;
             }
 
             final int requestSize = mRequestRecords.size();
@@ -240,7 +259,14 @@
                 }
             }
 
-            updatePendingStateLocked();
+            updatedPendingState = updatePendingStateLocked();
+        }
+
+        if (!updatedPendingState) {
+            // If the change in the supported states didn't result in a change of the pending state
+            // commitPendingState() will never be called and the callbacks will never be notified
+            // of the change.
+            notifyDeviceStateInfoChanged();
         }
 
         notifyRequestsOfStatusChangeIfNeeded();
@@ -265,23 +291,25 @@
     }
 
     /**
-     * Requests to set the base state. The request may not be honored under certain conditions, for
-     * example if the provided state is not supported.
+     * Sets the base state.
+     *
+     * @throws IllegalArgumentException if the {@code identifier} is not a supported state.
      *
      * @see #isSupportedStateLocked(int)
      */
     private void setBaseState(int identifier) {
+        boolean updatedPendingState;
         synchronized (mLock) {
-            if (mBaseState.isPresent() && mBaseState.get().getIdentifier() == identifier) {
-                // Base state hasn't changed. Nothing to do.
-                return;
-            }
-
-            final Optional<DeviceState> baseState = getStateLocked(identifier);
-            if (!baseState.isPresent()) {
+            final Optional<DeviceState> baseStateOptional = getStateLocked(identifier);
+            if (!baseStateOptional.isPresent()) {
                 throw new IllegalArgumentException("Base state is not supported");
             }
 
+            final DeviceState baseState = baseStateOptional.get();
+            if (mBaseState.equals(baseState)) {
+                // Base state hasn't changed. Nothing to do.
+                return;
+            }
             mBaseState = baseState;
 
             final int requestSize = mRequestRecords.size();
@@ -292,7 +320,14 @@
                 }
             }
 
-            updatePendingStateLocked();
+            updatedPendingState = updatePendingStateLocked();
+        }
+
+        if (!updatedPendingState) {
+            // If the change in base state didn't result in a change of the pending state
+            // commitPendingState() will never be called and the callbacks will never be notified
+            // of the change.
+            notifyDeviceStateInfoChanged();
         }
 
         notifyRequestsOfStatusChangeIfNeeded();
@@ -303,32 +338,39 @@
      * Tries to update the current pending state with the current requested state. Must call
      * {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being
      * changed.
+     *
+     * @return {@code true} if the pending state has changed as a result of this call, {@code false}
+     * otherwise.
      */
-    private void updatePendingStateLocked() {
+    private boolean updatePendingStateLocked() {
         if (mPendingState.isPresent()) {
             // Have pending state, can not configure a new state until the state is committed.
-            return;
+            return false;
         }
 
         final DeviceState stateToConfigure;
         if (!mRequestRecords.isEmpty()) {
             stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
+        } else if (isSupportedStateLocked(mBaseState.getIdentifier())) {
+            // Base state could have recently become unsupported after a change in supported states.
+            stateToConfigure = mBaseState;
         } else {
-            stateToConfigure = mBaseState.orElse(null);
+            stateToConfigure = null;
         }
 
         if (stateToConfigure == null) {
             // No currently requested state.
-            return;
+            return false;
         }
 
-        if (stateToConfigure == mCommittedState) {
+        if (stateToConfigure.equals(mCommittedState)) {
             // The state requesting to be committed already matches the current committed state.
-            return;
+            return false;
         }
 
         mPendingState = Optional.of(stateToConfigure);
         mIsPolicyWaitingForState = true;
+        return true;
     }
 
     /**
@@ -374,18 +416,22 @@
      */
     private void commitPendingState() {
         // Update the current state.
-        int newState;
         synchronized (mLock) {
             if (DEBUG) {
                 Slog.d(TAG, "Committing state: " + mPendingState);
             }
             mCommittedState = mPendingState.get();
-            newState = mCommittedState.getIdentifier();
 
             if (!mRequestRecords.isEmpty()) {
                 final OverrideRequestRecord topRequest =
                         mRequestRecords.get(mRequestRecords.size() - 1);
-                topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE);
+                if (topRequest.mRequestedState.getIdentifier() == mCommittedState.getIdentifier()) {
+                    // The top request could have come in while the service was awaiting callback
+                    // from the policy. In that case we only set it to active if it matches the
+                    // current committed state, otherwise it will be set to active when its
+                    // requested state is committed.
+                    topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE);
+                }
             }
 
             mPendingState = Optional.empty();
@@ -393,7 +439,7 @@
         }
 
         // Notify callbacks of a change.
-        notifyDeviceStateChanged(newState);
+        notifyDeviceStateInfoChanged();
 
         // Notify the top request that it's active.
         notifyRequestsOfStatusChangeIfNeeded();
@@ -402,14 +448,15 @@
         notifyPolicyIfNeeded();
     }
 
-    private void notifyDeviceStateChanged(int deviceState) {
+    private void notifyDeviceStateInfoChanged() {
         if (Thread.holdsLock(mLock)) {
             throw new IllegalStateException(
                     "Attempting to notify callbacks with service lock held.");
         }
 
-        // Grab the lock and copy the process records.
+        // Grab the lock and copy the process records and the current info.
         ArrayList<ProcessRecord> registeredProcesses;
+        DeviceStateInfo info;
         synchronized (mLock) {
             if (mProcessRecords.size() == 0) {
                 return;
@@ -419,11 +466,13 @@
             for (int i = 0; i < mProcessRecords.size(); i++) {
                 registeredProcesses.add(mProcessRecords.valueAt(i));
             }
+
+            info = getDeviceStateInfoLocked();
         }
 
         // After releasing the lock, send the notifications out.
         for (int i = 0; i < registeredProcesses.size(); i++) {
-            registeredProcesses.get(i).notifyDeviceStateAsync(deviceState);
+            registeredProcesses.get(i).notifyDeviceStateInfoAsync(info);
         }
     }
 
@@ -454,28 +503,20 @@
     }
 
     private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
-        int currentState;
-        ProcessRecord record;
-        // Grab the lock to register the callback and get the current state.
         synchronized (mLock) {
             if (mProcessRecords.contains(pid)) {
                 throw new SecurityException("The calling process has already registered an"
                         + " IDeviceStateManagerCallback.");
             }
 
-            record = new ProcessRecord(callback, pid);
+            ProcessRecord record = new ProcessRecord(callback, pid);
             try {
                 callback.asBinder().linkToDeath(record, 0);
             } catch (RemoteException ex) {
                 throw new RuntimeException(ex);
             }
-
             mProcessRecords.put(pid, record);
-            currentState = mCommittedState.getIdentifier();
         }
-
-        // Notify the callback of the state at registration.
-        record.notifyDeviceStateAsync(currentState);
     }
 
     private void handleProcessDied(ProcessRecord processRecord) {
@@ -528,10 +569,13 @@
                     new OverrideRequestRecord(processRecord, token, deviceState.get(), flags);
             mRequestRecords.add(request);
             processRecord.mRequestRecords.put(request.mToken, request);
-            // We don't set the status of the new request to ACTIVE here as it will be set in
-            // commitPendingState().
 
-            updatePendingStateLocked();
+            final boolean updatedPendingState = updatePendingStateLocked();
+            if (!updatedPendingState && !mPendingState.isPresent()) {
+                // We don't set the status of the new request to ACTIVE if the request updated the
+                // pending state as it will be set in commitPendingState().
+                request.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE, true /* markDirty */);
+            }
         }
 
         notifyRequestsOfStatusChangeIfNeeded();
@@ -626,9 +670,9 @@
             handleProcessDied(this);
         }
 
-        public void notifyDeviceStateAsync(int devicestate) {
+        public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) {
             try {
-                mCallback.onDeviceStateChanged(devicestate);
+                mCallback.onDeviceStateInfoChanged(info);
             } catch (RemoteException ex) {
                 Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
                         ex);
@@ -752,6 +796,13 @@
     /** Implementation of {@link IDeviceStateManager} published as a binder service. */
     private final class BinderService extends IDeviceStateManager.Stub {
         @Override // Binder call
+        public DeviceStateInfo getDeviceStateInfo() {
+            synchronized (mLock) {
+                return getDeviceStateInfoLocked();
+            }
+        }
+
+        @Override // Binder call
         public void registerCallback(IDeviceStateManagerCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("Device state callback must not be null.");
@@ -767,16 +818,6 @@
         }
 
         @Override // Binder call
-        public int[] getSupportedDeviceStates() {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                return getSupportedStateIdentifiers();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override // Binder call
         public void requestState(IBinder token, int state, int flags) {
             getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
                     "Permission required to request device state.");
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 6cc55a6..f346600 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -64,13 +64,13 @@
 
     private void printState(PrintWriter pw) {
         DeviceState committedState = mService.getCommittedState();
-        Optional<DeviceState> baseState = mService.getBaseState();
+        DeviceState baseState = mService.getBaseState();
         Optional<DeviceState> overrideState = mService.getOverrideState();
 
         pw.println("Committed state: " + committedState);
         if (overrideState.isPresent()) {
             pw.println("----------------------");
-            pw.println("Base state: " + baseState.orElse(null));
+            pw.println("Base state: " + baseState);
             pw.println("Override state: " + overrideState.get());
         }
     }
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index 91674cd..1acd5d0 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -16,17 +16,26 @@
 
 package com.android.server.display;
 
-import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
-import android.text.TextUtils;
+import android.os.Environment;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.DisplayAddress;
 
+import com.android.server.display.config.layout.Layouts;
+import com.android.server.display.config.layout.XmlParser;
 import com.android.server.display.layout.Layout;
 
-import java.util.Arrays;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.datatype.DatatypeConfigurationException;
 
 /**
  * Mapping from device states into {@link Layout}s. This allows us to map device
@@ -39,11 +48,14 @@
 
     public static final int STATE_DEFAULT = DeviceStateManager.INVALID_DEVICE_STATE;
 
+    private static final String CONFIG_FILE_PATH =
+            "etc/displayconfig/display_layout_configuration.xml";
+
     private final SparseArray<Layout> mLayoutMap = new SparseArray<>();
 
-    DeviceStateToLayoutMap(Context context) {
-        mLayoutMap.append(STATE_DEFAULT, new Layout());
-        loadFoldedDisplayConfig(context);
+    DeviceStateToLayoutMap() {
+        loadLayoutsFromConfig();
+        createLayout(STATE_DEFAULT);
     }
 
     public void dumpLocked(IndentingPrintWriter ipw) {
@@ -76,48 +88,36 @@
     }
 
     /**
-     * Loads config.xml-specified folded configurations for foldable devices.
+     * Reads display-layout-configuration files to get the layouts to use for this device.
      */
-    private void loadFoldedDisplayConfig(Context context) {
-        final String[] strDisplayIds = context.getResources().getStringArray(
-                com.android.internal.R.array.config_internalFoldedPhysicalDisplayIds);
-        if (strDisplayIds.length != 2 || TextUtils.isEmpty(strDisplayIds[0])
-                || TextUtils.isEmpty(strDisplayIds[1])) {
-            Slog.w(TAG, "Folded display configuration invalid: [" + Arrays.toString(strDisplayIds)
-                    + "]");
+    private void loadLayoutsFromConfig() {
+        final File configFile = Environment.buildPath(
+                Environment.getVendorDirectory(), CONFIG_FILE_PATH);
+
+        if (!configFile.exists()) {
             return;
         }
 
-        final long[] displayIds;
-        try {
-            displayIds = new long[] {
-                Long.parseLong(strDisplayIds[0]),
-                Long.parseLong(strDisplayIds[1])
-            };
-        } catch (NumberFormatException nfe) {
-            Slog.w(TAG, "Folded display config non numerical: " + Arrays.toString(strDisplayIds));
-            return;
-        }
-
-        final int[] foldedDeviceStates = context.getResources().getIntArray(
-                com.android.internal.R.array.config_foldedDeviceStates);
-        final int[] unfoldedDeviceStates = context.getResources().getIntArray(
-                com.android.internal.R.array.config_unfoldedDeviceStates);
-        // Only add folded states if folded state config is not empty
-        if (foldedDeviceStates.length == 0 || unfoldedDeviceStates.length == 0) {
-            return;
-        }
-
-        for (int state : foldedDeviceStates) {
-            // Create the folded state layout
-            createLayout(state).createDisplayLocked(
-                    DisplayAddress.fromPhysicalDisplayId(displayIds[0]), true /*isDefault*/);
-        }
-
-        for (int state : unfoldedDeviceStates) {
-            // Create the unfolded state layout
-            createLayout(state).createDisplayLocked(
-                    DisplayAddress.fromPhysicalDisplayId(displayIds[1]), true /*isDefault*/);
+        Slog.i(TAG, "Loading display layouts from " + configFile);
+        try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
+            final Layouts layouts = XmlParser.read(in);
+            if (layouts == null) {
+                Slog.i(TAG, "Display layout config not found: " + configFile);
+                return;
+            }
+            for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) {
+                final int state = l.getState().intValue();
+                final Layout layout = createLayout(state);
+                for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
+                    layout.createDisplayLocked(
+                            DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
+                            d.getIsDefault(),
+                            d.getEnabled());
+                }
+            }
+        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+            Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: "
+                    + configFile, e);
         }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6fc3e09..174d4b2 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -423,7 +423,7 @@
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
-        mLogicalDisplayMapper = new LogicalDisplayMapper(context, mDisplayDeviceRepo,
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo,
                 new LogicalDisplayListener());
         mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
         mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
@@ -532,7 +532,7 @@
 
             DeviceStateManager deviceStateManager =
                     mContext.getSystemService(DeviceStateManager.class);
-            deviceStateManager.addDeviceStateListener(new HandlerExecutor(mHandler),
+            deviceStateManager.registerCallback(new HandlerExecutor(mHandler),
                     new DeviceStateListener());
 
             scheduleTraversalLocked(false);
@@ -1178,7 +1178,10 @@
 
     private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
         final int displayId = display.getDisplayIdLocked();
-        mDisplayPowerControllers.removeReturnOld(displayId).stop();
+        final DisplayPowerController dpc = mDisplayPowerControllers.removeReturnOld(displayId);
+        if (dpc != null) {
+            dpc.stop();
+        }
         mDisplayStates.delete(displayId);
         mDisplayBrightnesses.delete(displayId);
         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1200,9 +1203,6 @@
         // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            // TODO - b/170498827 The rules regarding what display state to apply to each
-            // display will depend on the configuration/mapping of logical displays.
-            // Clean up LogicalDisplay.isEnabled() mechanism once this is fixed.
             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
             final int state;
             final int displayId = display.getDisplayIdLocked();
@@ -2976,9 +2976,9 @@
     /**
      * Listens to changes in device state and reports the state to LogicalDisplayMapper.
      */
-    class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+    class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
         @Override
-        public void onDeviceStateChanged(int deviceState) {
+        public void onStateChanged(int deviceState) {
             synchronized (mSyncRoot) {
                 mLogicalDisplayMapper.setDeviceStateLocked(deviceState);
             }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index dce6bd8..645ca7a 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -31,7 +31,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
@@ -80,6 +79,8 @@
     // specific display.
     private static final int GLOBAL_ID = -1;
 
+    private static final int INVALID_DISPLAY_MODE_ID = -1;
+
     // The tolerance within which we consider something approximately equals.
     private static final float FLOAT_TOLERANCE = 0.01f;
 
@@ -322,12 +323,30 @@
                                 appRequestSummary.maxRefreshRate));
             }
 
-            // If the application requests a given mode with preferredModeId function, it will be
-            // stored as baseModeId.
-            int baseModeId = defaultMode.getModeId();
-            if (availableModes.length > 0) {
+            int baseModeId = INVALID_DISPLAY_MODE_ID;
+
+            // Select the default mode if available. This is important because SurfaceFlinger
+            // can do only seamless switches by default. Some devices (e.g. TV) don't support
+            // seamless switching so the mode we select here won't be changed.
+            for (int availableMode : availableModes) {
+                if (availableMode == defaultMode.getModeId()) {
+                    baseModeId = defaultMode.getModeId();
+                    break;
+                }
+            }
+
+            // If the application requests a display mode by setting
+            // LayoutParams.preferredDisplayModeId, it will be the only available mode and it'll
+            // be stored as baseModeId.
+            if (baseModeId == INVALID_DISPLAY_MODE_ID && availableModes.length > 0) {
                 baseModeId = availableModes[0];
             }
+
+            if (baseModeId == INVALID_DISPLAY_MODE_ID) {
+                throw new IllegalStateException("Can't select a base display mode for display "
+                        + displayId + ". The votes are " + mVotesByDisplay.valueAt(displayId));
+            }
+
             if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
                 Display.Mode baseMode = null;
                 for (Display.Mode mode : modes) {
@@ -351,6 +370,7 @@
 
             boolean allowGroupSwitching =
                     mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
+
             return new DesiredDisplayModeSpecs(baseModeId,
                     allowGroupSwitching,
                     new RefreshRateRange(
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 22c12e9..d6826be 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -16,7 +16,6 @@
 
 package com.android.server.display;
 
-import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.SystemProperties;
 import android.text.TextUtils;
@@ -90,7 +89,6 @@
     private final DisplayDeviceRepository mDisplayDeviceRepo;
     private final DeviceStateToLayoutMap mDeviceStateToLayoutMap;
     private final Listener mListener;
-    private final int[] mFoldedDeviceStates;
 
     /**
      * Has an entry for every logical display that the rest of the system has been notified about.
@@ -122,16 +120,12 @@
     private Layout mCurrentLayout = null;
     private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
 
-    LogicalDisplayMapper(Context context, DisplayDeviceRepository repo, Listener listener) {
+    LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener) {
         mDisplayDeviceRepo = repo;
         mListener = listener;
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         mDisplayDeviceRepo.addListener(this);
-
-        mFoldedDeviceStates = context.getResources().getIntArray(
-                com.android.internal.R.array.config_foldedDeviceStates);
-
-        mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(context);
+        mDeviceStateToLayoutMap = new DeviceStateToLayoutMap();
     }
 
     @Override
@@ -311,6 +305,7 @@
                 if (wasPreviouslyUpdated) {
                     // The display isn't actually removed from our internal data structures until
                     // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}.
+                    Slog.i(TAG, "Removing display: " + displayId);
                     mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
                 } else {
                     // This display never left this class, safe to remove without notification
@@ -320,6 +315,7 @@
 
             // The display is new.
             } else if (!wasPreviouslyUpdated) {
+                Slog.i(TAG, "Adding new display: " + displayId + ": " + newDisplayInfo);
                 assignDisplayGroupLocked(display);
                 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED);
 
@@ -455,19 +451,23 @@
             newGroup = new DisplayGroup(groupId);
             mDisplayGroups.append(groupId, newGroup);
         }
-
-        // Add/remove display from the groups.
-        newGroup.addDisplayLocked(display);
-        if (oldGroup != null && oldGroup != newGroup) {
-            oldGroup.removeDisplayLocked(display);
+        if (oldGroup != newGroup) {
+            if (oldGroup != null) {
+                oldGroup.removeDisplayLocked(display);
+            }
+            newGroup.addDisplayLocked(display);
+            display.updateDisplayGroupIdLocked(groupId);
+            Slog.i(TAG, "Setting new display group " + groupId + " for display "
+                    + displayId + ", from previous group: "
+                    + (oldGroup != null ? oldGroup.getGroupId() : "null"));
         }
     }
 
     /**
-     * Resets the current layout in preparation for a new layout; essentially just marks
-     * all the currently layed out displays as disabled. This ensures the display devices
-     * are turned off. If they are meant to be used in the new layout,
-     * {@link #applyLayoutLocked()} will reenabled them.
+     * Resets the current layout in preparation for a new layout. Layouts can specify if some
+     * displays should be disabled (OFF). When switching from one layout to another, we go
+     * through each of the displays and make sure any displays we might have disabled are
+     * enabled again.
      */
     private void resetLayoutLocked() {
         final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState);
@@ -475,7 +475,7 @@
             final Layout.Display displayLayout = layout.getAt(i);
             final LogicalDisplay display = getDisplayLocked(displayLayout.getLogicalDisplayId());
             if (display != null) {
-                enableDisplayLocked(display, false);
+                enableDisplayLocked(display, true); // Reset all displays back to enabled
             }
         }
     }
@@ -497,7 +497,8 @@
 
             // If the underlying display-device we want to use for this display
             // doesn't exist, then skip it. This can happen at startup as display-devices
-            // trickle in one at a time, or if the layout has an error.
+            // trickle in one at a time. When the new display finally shows up, the layout is
+            // recalculated so that the display is properly added to the current layout.
             final DisplayAddress address = displayLayout.getAddress();
             final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
             if (device == null) {
@@ -520,7 +521,7 @@
             if (newDisplay != oldDisplay) {
                 newDisplay.swapDisplaysLocked(oldDisplay);
             }
-            enableDisplayLocked(newDisplay, true);
+            enableDisplayLocked(newDisplay, displayLayout.isEnabled());
         }
     }
 
@@ -539,13 +540,7 @@
         final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
         display.updateLocked(mDisplayDeviceRepo);
         mLogicalDisplays.put(displayId, display);
-
-        // Internal displays start off disabled. The display is enabled later if it is part of the
-        // currently selected display layout.
-        final boolean isEnabled = device != null
-                && device.getDisplayDeviceInfoLocked().type != Display.TYPE_INTERNAL;
-        enableDisplayLocked(display, isEnabled);
-
+        enableDisplayLocked(display, device != null);
         return display;
     }
 
@@ -576,7 +571,7 @@
         final Layout layoutSet = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
-        layoutSet.createDisplayLocked(info.address, isDefault);
+        layoutSet.createDisplayLocked(info.address, isDefault, true /* isEnabled */);
     }
 
     private int assignLayerStackLocked(int displayId) {
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index 18f39e6..ef33667 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -57,7 +57,7 @@
      * @return The new layout.
      */
     public Display createDisplayLocked(
-            @NonNull DisplayAddress address, boolean isDefault) {
+            @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled) {
         if (contains(address)) {
             Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
             return null;
@@ -74,7 +74,7 @@
         // different layouts, a logical display can be destroyed and later recreated with the
         // same logical display ID.
         final int logicalDisplayId = assignDisplayIdLocked(isDefault);
-        final Display layout = new Display(address, logicalDisplayId);
+        final Display layout = new Display(address, logicalDisplayId, isEnabled);
 
         mDisplays.add(layout);
         return layout;
@@ -130,17 +130,25 @@
      * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s.
      */
     public static class Display {
+        // Address of the display device to map to this display.
         private final DisplayAddress mAddress;
+
+        // Logical Display ID to apply to this display.
         private final int mLogicalDisplayId;
 
-        Display(@NonNull DisplayAddress address, int logicalDisplayId) {
+        // Indicates that this display is not usable and should remain off.
+        private final boolean mIsEnabled;
+
+        Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled) {
             mAddress = address;
             mLogicalDisplayId = logicalDisplayId;
+            mIsEnabled = isEnabled;
         }
 
         @Override
         public String toString() {
-            return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId + "}";
+            return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId
+                    + "(" + (mIsEnabled ? "ON" : "OFF") + ")}";
         }
 
         public DisplayAddress getAddress() {
@@ -150,5 +158,9 @@
         public int getLogicalDisplayId() {
             return mLogicalDisplayId;
         }
+
+        public boolean isEnabled() {
+            return mIsEnabled;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java b/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java
deleted file mode 100644
index b082b25..0000000
--- a/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.graphics.fonts;
-
-import android.annotation.NonNull;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * A class to detect font-related native crash.
- *
- * <p>If a fs-verity protected file is accessed through mmap and corrupted file block is detected,
- * SIGBUG signal is generated and the process will crash. To find corrupted files and remove them,
- * we use a marker file to detect crash.
- * <ol>
- *     <li>Create a marker file before reading fs-verity protected font files.
- *     <li>Delete the marker file after reading font files successfully.
- *     <li>If the marker file is found in the next process startup, it means that the process
- *         crashed before. We will delete font files to prevent crash loop.
- * </ol>
- *
- * <p>Example usage:
- * <pre>
- *     FontCrashDetector detector = new FontCrashDetector(new File("/path/to/marker_file"));
- *     if (detector.hasCrashed()) {
- *         // Do cleanup
- *     }
- *     try (FontCrashDetector.MonitoredBlock b = detector.start()) {
- *         // Read files
- *     }
- * </pre>
- *
- * <p>This class DOES NOT detect Java exceptions. If a Java exception is thrown while monitoring
- * crash, the marker file will be deleted. Creating and deleting marker files are not lightweight.
- * Please use this class sparingly with caution.
- */
-/* package */ final class FontCrashDetector {
-
-    private static final String TAG = "FontCrashDetector";
-
-    @NonNull
-    private final File mMarkerFile;
-
-    /* package */ FontCrashDetector(@NonNull File markerFile) {
-        mMarkerFile = markerFile;
-    }
-
-    /* package */ boolean hasCrashed() {
-        return mMarkerFile.exists();
-    }
-
-    /* package */ void clear() {
-        if (!mMarkerFile.delete()) {
-            Slog.e(TAG, "Could not delete marker file: " + mMarkerFile);
-        }
-    }
-
-    /** Starts crash monitoring. */
-    /* package */ MonitoredBlock start() {
-        try {
-            mMarkerFile.createNewFile();
-        } catch (IOException e) {
-            Slog.e(TAG, "Could not create marker file: " + mMarkerFile, e);
-        }
-        return new MonitoredBlock();
-    }
-
-    /** A helper class to monitor crash with try-with-resources syntax. */
-    /* package */ class MonitoredBlock implements AutoCloseable {
-        /** Ends crash monitoring. */
-        @Override
-        public void close() {
-            clear();
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 01e839d..900ec90 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -63,7 +63,6 @@
     private static final String TAG = "FontManagerService";
 
     private static final String FONT_FILES_DIR = "/data/fonts/files";
-    private static final String CRASH_MARKER_FILE = "/data/fonts/config/crash.txt";
 
     @Override
     public FontConfig getFontConfig() {
@@ -200,10 +199,6 @@
     private final Object mUpdatableFontDirLock = new Object();
 
     @GuardedBy("mUpdatableFontDirLock")
-    @NonNull
-    private final FontCrashDetector mFontCrashDetector;
-
-    @GuardedBy("mUpdatableFontDirLock")
     @Nullable
     private final UpdatableFontDir mUpdatableFontDir;
 
@@ -217,7 +212,6 @@
 
     private FontManagerService(Context context) {
         mContext = context;
-        mFontCrashDetector = new FontCrashDetector(new File(CRASH_MARKER_FILE));
         mUpdatableFontDir = createUpdatableFontDir();
         initialize();
     }
@@ -244,19 +238,8 @@
                 }
                 return;
             }
-            if (mFontCrashDetector.hasCrashed()) {
-                Slog.i(TAG, "Crash detected. Clearing font updates.");
-                try {
-                    mUpdatableFontDir.clearUpdates();
-                } catch (SystemFontException e) {
-                    Slog.e(TAG, "Failed to clear updates.", e);
-                }
-                mFontCrashDetector.clear();
-            }
-            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
-                mUpdatableFontDir.loadFontFileMap();
-                updateSerializedFontMap();
-            }
+            mUpdatableFontDir.loadFontFileMap();
+            updateSerializedFontMap();
         }
     }
 
@@ -286,10 +269,8 @@
                         FontManager.RESULT_ERROR_VERSION_MISMATCH,
                         "The base config version is older than current.");
             }
-            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
-                mUpdatableFontDir.update(requests);
-                updateSerializedFontMap();
-            }
+            mUpdatableFontDir.update(requests);
+            updateSerializedFontMap();
         }
     }
 
@@ -300,10 +281,8 @@
                     "The font updater is disabled.");
         }
         synchronized (mUpdatableFontDirLock) {
-            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
-                mUpdatableFontDir.clearUpdates();
-                updateSerializedFontMap();
-            }
+            mUpdatableFontDir.clearUpdates();
+            updateSerializedFontMap();
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8d6bcad..18f7a06865 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -666,8 +666,19 @@
                         mSelectRequestBuffer.process();
                         resetSelectRequestBuffer();
 
-                        addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
-                        addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this));
+                        List<HotplugDetectionAction> hotplugActions
+                                = getActions(HotplugDetectionAction.class);
+                        if (hotplugActions.isEmpty()) {
+                            addAndStartAction(
+                                    new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
+                        }
+
+                        List<PowerStatusMonitorAction> powerStatusActions
+                                = getActions(PowerStatusMonitorAction.class);
+                        if (powerStatusActions.isEmpty()) {
+                            addAndStartAction(
+                                    new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this));
+                        }
 
                         HdmiDeviceInfo avr = getAvrDeviceInfo();
                         if (avr != null) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
index 8c40424..6f7473d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
@@ -106,9 +106,7 @@
         addHandler(Constants.MESSAGE_SET_STREAM_PATH, mBystander);
         addHandler(Constants.MESSAGE_STANDBY, mBystander);
         addHandler(Constants.MESSAGE_SET_MENU_LANGUAGE, mBystander);
-        addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBystander);
         addHandler(Constants.MESSAGE_USER_CONTROL_RELEASED, mBystander);
-        addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBystander);
         addHandler(Constants.MESSAGE_FEATURE_ABORT, mBystander);
         addHandler(Constants.MESSAGE_INACTIVE_SOURCE, mBystander);
         addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander);
@@ -133,6 +131,8 @@
         addHandler(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, mBypasser);
         addHandler(Constants.MESSAGE_GIVE_OSD_NAME, mBypasser);
         addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser);
+        addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser);
+        addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser);
 
         addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b4d9b01..115cafed 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -221,7 +221,7 @@
     private int mHdmiCecVolumeControl;
 
     // Make sure HdmiCecConfig is instantiated and the XMLs are read.
-    private final HdmiCecConfig mHdmiCecConfig;
+    private HdmiCecConfig mHdmiCecConfig;
 
     /**
      * Interface to report send result.
@@ -580,6 +580,11 @@
         mHdmiCecNetwork = hdmiCecNetwork;
     }
 
+    @VisibleForTesting
+    void setHdmiCecConfig(HdmiCecConfig hdmiCecConfig) {
+        mHdmiCecConfig = hdmiCecConfig;
+    }
+
     public HdmiCecNetwork getHdmiCecNetwork() {
         return mHdmiCecNetwork;
     }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index bd577f3..016c5ed 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -1052,6 +1052,9 @@
         public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
             if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
             final String property = uri.getLastPathSegment();
+            if (property == null) {
+                return;
+            }
             if (property.equals(getServiceSettingsProperty())
                     || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
                 synchronized (mLock) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bbe52bc..edb5d97 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -590,10 +590,13 @@
             for (int i = viewports.size() - 1; i >= 0; --i) {
                 final DisplayViewport v = vArray[i] = viewports.get(i).makeCopy();
                 // deviceWidth/Height are apparently in "rotated" space, so flip them if needed.
-                int dw = (v.orientation % 2) == 0 ? v.deviceWidth : v.deviceHeight;
-                int dh = (v.orientation % 2) == 0 ? v.deviceHeight : v.deviceWidth;
-                v.logicalFrame.set(0, 0, dw, dh);
-                v.physicalFrame.set(0, 0, dw, dh);
+                if (v.orientation % 2 != 0) {
+                    final int dw = v.deviceWidth;
+                    v.deviceWidth = v.deviceHeight;
+                    v.deviceHeight = dw;
+                }
+                v.logicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight);
+                v.physicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight);
                 v.orientation = 0;
             }
         } else {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0dc7445..4e8fcf7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -159,6 +159,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.CallbackUtils;
 import com.android.internal.inputmethod.IBooleanResultCallback;
+import com.android.internal.inputmethod.IIInputContentUriTokenResultCallback;
 import com.android.internal.inputmethod.IInputBindResultResultCallback;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
@@ -2620,9 +2621,8 @@
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
                 // Dispatch display id for InputMethodService to update context display.
-                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
-                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken,
-                        mMethodMap.get(mCurMethodId).getConfigChanges()));
+                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
                 scheduleNotifyImeUidToAudioService(mCurMethodUid);
                 if (mCurClient != null) {
                     clearClientSessionLocked(mCurClient);
@@ -3537,6 +3537,20 @@
         boolean didStart = false;
 
         InputBindResult res = null;
+        // We shows the IME when the system allows the IME focused target window to restore the
+        // IME visibility (e.g. switching to the app task when last time the IME is visible).
+        if (isTextEditor && mWindowManagerInternal.shouldRestoreImeVisibility(windowToken)) {
+            if (attribute != null) {
+                res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+                        attribute, startInputFlags, startInputReason);
+                showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
+                        SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
+            } else {
+                res = InputBindResult.NULL_EDITOR_INFO;
+            }
+            return res;
+        }
+
         switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
             case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
                 if (!sameWindowFocused && (!isTextEditor || !doAutoShow)) {
@@ -4464,8 +4478,7 @@
                     }
                     final IBinder token = (IBinder) args.arg2;
                     ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
-                            new InputMethodPrivilegedOperationsImpl(this, token),
-                            (int) args.arg3);
+                            new InputMethodPrivilegedOperationsImpl(this, token));
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -5871,87 +5884,102 @@
 
         @BinderThread
         @Override
-        public void setImeWindowStatus(int vis, int backDisposition) {
-            mImms.setImeWindowStatus(mToken, vis, backDisposition);
+        public void setImeWindowStatus(int vis, int backDisposition,
+                IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.setImeWindowStatus(mToken, vis, backDisposition));
         }
 
         @BinderThread
         @Override
-        public void reportStartInput(IBinder startInputToken) {
-            mImms.reportStartInput(mToken, startInputToken);
+        public void reportStartInput(IBinder startInputToken, IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.reportStartInput(mToken, startInputToken));
         }
 
         @BinderThread
         @Override
-        public IInputContentUriToken createInputContentUriToken(Uri contentUri,
-                String packageName) {
-            return mImms.createInputContentUriToken(mToken, contentUri, packageName);
+        public void createInputContentUriToken(Uri contentUri, String packageName,
+                IIInputContentUriTokenResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.createInputContentUriToken(mToken, contentUri, packageName));
         }
 
         @BinderThread
         @Override
-        public void reportFullscreenMode(boolean fullscreen) {
-            mImms.reportFullscreenMode(mToken, fullscreen);
+        public void reportFullscreenMode(boolean fullscreen, IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.reportFullscreenMode(mToken, fullscreen));
         }
 
         @BinderThread
         @Override
-        public void setInputMethod(String id) {
-            mImms.setInputMethod(mToken, id);
+        public void setInputMethod(String id, IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> mImms.setInputMethod(mToken, id));
         }
 
         @BinderThread
         @Override
-        public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
-            mImms.setInputMethodAndSubtype(mToken, id, subtype);
+        public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype,
+                IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.setInputMethodAndSubtype(mToken, id, subtype));
         }
 
         @BinderThread
         @Override
-        public void hideMySoftInput(int flags) {
-            mImms.hideMySoftInput(mToken, flags);
+        public void hideMySoftInput(int flags, IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> mImms.hideMySoftInput(mToken, flags));
         }
 
         @BinderThread
         @Override
-        public void showMySoftInput(int flags) {
-            mImms.showMySoftInput(mToken, flags);
+        public void showMySoftInput(int flags, IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> mImms.showMySoftInput(mToken, flags));
         }
 
         @BinderThread
         @Override
-        public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
-            mImms.updateStatusIcon(mToken, packageName, iconId);
+        public void updateStatusIcon(String packageName, @DrawableRes int iconId,
+                IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.updateStatusIcon(mToken, packageName, iconId));
         }
 
         @BinderThread
         @Override
-        public boolean switchToPreviousInputMethod() {
-            return mImms.switchToPreviousInputMethod(mToken);
+        public void switchToPreviousInputMethod(IBooleanResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> mImms.switchToPreviousInputMethod(mToken));
         }
 
         @BinderThread
         @Override
-        public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
-            return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
+        public void switchToNextInputMethod(boolean onlyCurrentIme,
+                IBooleanResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
         }
 
         @BinderThread
         @Override
-        public boolean shouldOfferSwitchingToNextInputMethod() {
-            return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
+        public void shouldOfferSwitchingToNextInputMethod(
+                IBooleanResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.shouldOfferSwitchingToNextInputMethod(mToken));
         }
 
         @BinderThread
         @Override
-        public void notifyUserAction() {
-            mImms.notifyUserAction(mToken);
+        public void notifyUserAction(IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> mImms.notifyUserAction(mToken));
         }
 
         @BinderThread
         @Override
-        public void applyImeVisibility(IBinder windowToken, boolean setVisible) {
-            mImms.applyImeVisibility(mToken, windowToken, setVisible);
+        public void applyImeVisibility(IBinder windowToken, boolean setVisible,
+                IVoidResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback,
+                    () -> mImms.applyImeVisibility(mToken, windowToken, setVisible));
         }
     }
 }
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index 3ac148d..c93c4b1 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -24,7 +24,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
-import com.android.server.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher;
 
 import java.util.Collections;
 
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index 6ea4bd2..e1c8700 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -25,8 +25,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import com.android.server.ServiceWatcher;
-import com.android.server.ServiceWatcher.BoundService;
+import com.android.server.servicewatcher.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher.BoundService;
 
 /**
  * Proxy class to bind GmsCore to the ActivityRecognitionHardware.
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
index bdfa6d7..c707149 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
@@ -29,7 +29,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.server.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher;
 
 import java.util.Objects;
 
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index fef30f9..2aa6f28 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -29,6 +29,8 @@
 import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
 import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
 import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+import static android.os.PowerWhitelistManager.REASON_LOCATION_PROVIDER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 
 import static com.android.server.location.LocationManagerService.D;
 import static com.android.server.location.LocationManagerService.TAG;
@@ -227,7 +229,10 @@
             BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setDontSendToRestrictedApps(true);
             // allows apps to start a fg service in response to a location PI
-            options.setTemporaryAppWhitelistDuration(TEMPORARY_APP_ALLOWLIST_DURATION_MS);
+            options.setTemporaryAppAllowlist(TEMPORARY_APP_ALLOWLIST_DURATION_MS,
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    REASON_LOCATION_PROVIDER,
+                    "");
 
             Intent intent = new Intent().putExtra(KEY_LOCATION_CHANGED,
                     locationResult.getLastLocation());
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index 44b62b3..c86e49b 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -36,9 +36,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.ServiceWatcher;
-import com.android.server.ServiceWatcher.BoundService;
 import com.android.server.location.provider.AbstractLocationProvider;
+import com.android.server.servicewatcher.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher.BoundService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 87e170a..cb0a6688 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -29,6 +29,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
+import android.os.PowerWhitelistManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -195,8 +196,9 @@
         mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
 
         final BroadcastOptions options = BroadcastOptions.makeBasic();
-        options.setTemporaryAppWhitelistDuration(
-                FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS);
+        options.setTemporaryAppAllowlist(FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS,
+                PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                PowerWhitelistManager.REASON_MEDIA_BUTTON, "");
         if (mPendingIntent != null) {
             if (DEBUG_KEY_EVENT) {
                 Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3cc32be..851ea3d 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -35,7 +35,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.os.Handler;
-import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -63,7 +62,6 @@
     @NonNull private final Handler mHandler;
     @NonNull private final Vpn mVpn;
     @NonNull private final VpnProfile mProfile;
-    @NonNull private final KeyStore mKeyStore;
 
     @NonNull private final Object mStateLock = new Object();
 
@@ -132,7 +130,6 @@
 
     public LockdownVpnTracker(@NonNull Context context,
             @NonNull Handler handler,
-            @NonNull KeyStore keyStore,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
         mContext = Objects.requireNonNull(context);
@@ -140,7 +137,6 @@
         mHandler = Objects.requireNonNull(handler);
         mVpn = Objects.requireNonNull(vpn);
         mProfile = Objects.requireNonNull(profile);
-        mKeyStore = Objects.requireNonNull(keyStore);
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
@@ -212,7 +208,7 @@
                 //    network is the system default. So, if the VPN  is up and underlying network
                 //    (e.g., wifi) disconnects, CS will inform apps that the VPN's capabilities have
                 //    changed to match the new default network (e.g., cell).
-                mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, network, egressProp);
+                mVpn.startLegacyVpnPrivileged(mProfile, network, egressProp);
             } catch (IllegalStateException e) {
                 mAcceptedEgressIface = null;
                 Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 5b9a11b..e0f5346 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,7 +24,6 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
 import static android.net.NetworkStack.checkNetworkStackPermission;
@@ -45,6 +44,7 @@
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UNSUPPORTED;
@@ -97,7 +97,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkIdentity;
 import android.net.NetworkStack;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStats.NonMonotonicObserver;
 import android.net.NetworkStatsHistory;
@@ -296,7 +296,7 @@
     /** Last states of all networks sent from ConnectivityService. */
     @GuardedBy("mStatsLock")
     @Nullable
-    private NetworkState[] mLastNetworkStates = null;
+    private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null;
 
     private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
             new DropBoxNonMonotonicObserver();
@@ -378,8 +378,9 @@
                 }
                 case MSG_UPDATE_IFACES: {
                     // If no cached states, ignore.
-                    if (mLastNetworkStates == null) break;
-                    updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface);
+                    if (mLastNetworkStateSnapshots == null) break;
+                    // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing.
+                    updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
                     break;
                 }
                 case MSG_PERFORM_POLL_REGISTER_ALERT: {
@@ -967,10 +968,9 @@
         }
     }
 
-    @Override
     public void forceUpdateIfaces(
             Network[] defaultNetworks,
-            NetworkState[] networkStates,
+            NetworkStateSnapshot[] networkStates,
             String activeIface,
             UnderlyingNetworkInfo[] underlyingNetworkInfos) {
         checkNetworkStackPermission(mContext);
@@ -1248,13 +1248,13 @@
 
     private void updateIfaces(
             Network[] defaultNetworks,
-            NetworkState[] networkStates,
+            NetworkStateSnapshot[] snapshots,
             String activeIface) {
         synchronized (mStatsLock) {
             mWakeLock.acquire();
             try {
                 mActiveIface = activeIface;
-                updateIfacesLocked(defaultNetworks, networkStates);
+                updateIfacesLocked(defaultNetworks, snapshots);
             } finally {
                 mWakeLock.release();
             }
@@ -1262,13 +1262,13 @@
     }
 
     /**
-     * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link
-     * NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
+     * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to
+     * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
      * they are combined under a single {@link NetworkIdentitySet}.
      */
     @GuardedBy("mStatsLock")
-    private void updateIfacesLocked(@Nullable Network[] defaultNetworks,
-            @NonNull NetworkState[] states) {
+    private void updateIfacesLocked(@NonNull Network[] defaultNetworks,
+            @NonNull NetworkStateSnapshot[] snapshots) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
@@ -1283,26 +1283,24 @@
         // Rebuild active interfaces based on connected networks
         mActiveIfaces.clear();
         mActiveUidIfaces.clear();
-        if (defaultNetworks != null) {
-            // Caller is ConnectivityService. Update the list of default networks.
-            mDefaultNetworks = defaultNetworks;
-        }
+        // Update the list of default networks.
+        mDefaultNetworks = defaultNetworks;
 
-        mLastNetworkStates = states;
+        mLastNetworkStateSnapshots = snapshots;
 
         final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
         final ArraySet<String> mobileIfaces = new ArraySet<>();
-        for (NetworkState state : states) {
-            final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType);
-            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+        for (NetworkStateSnapshot snapshot : snapshots) {
+            final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType);
+            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network);
             final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
-                    : getSubTypeForState(state);
-            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+                    : getSubTypeForStateSnapshot(snapshot);
+            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
                     isDefault, subType);
 
             // Traffic occurring on the base interface is always counted for
             // both total usage and UID details.
-            final String baseIface = state.linkProperties.getInterfaceName();
+            final String baseIface = snapshot.linkProperties.getInterfaceName();
             if (baseIface != null) {
                 findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
                 findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
@@ -1312,7 +1310,7 @@
                 // If IMS is metered, then the IMS network usage has already included VT usage.
                 // VT is considered always metered in framework's layer. If VT is not metered
                 // per carrier's policy, modem will report 0 usage for VT calls.
-                if (state.networkCapabilities.hasCapability(
+                if (snapshot.networkCapabilities.hasCapability(
                         NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
 
                     // Copy the identify from IMS one but mark it as metered.
@@ -1358,7 +1356,7 @@
             // (or non eBPF offloaded) TX they would appear on both, however egress interface
             // accounting is explicitly bypassed for traffic from the clat uid.
             //
-            final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
+            final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks();
             for (LinkProperties stackedLink : stackedLinks) {
                 final String stackedIface = stackedLink.getInterfaceName();
                 if (stackedIface != null) {
@@ -1381,7 +1379,7 @@
      * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
      * transport types do not actually fill this value.
      */
-    private int getSubTypeForState(@NonNull NetworkState state) {
+    private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) {
         if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
             return 0;
         }
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 9a9b14c..b34611b 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -207,35 +207,37 @@
         @Override
         public void onServiceDisconnected(ComponentName arg0) {
             Slog.i(TAG, "DataLoader " + mId + " disconnected, but will try to recover");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
         }
 
         @Override
         public void onBindingDied(ComponentName name) {
             Slog.i(TAG, "DataLoader " + mId + " died");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
         }
 
         @Override
         public void onNullBinding(ComponentName name) {
             Slog.i(TAG, "DataLoader " + mId + " failed to start");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
         }
 
         @Override
         public void binderDied() {
             Slog.i(TAG, "DataLoader " + mId + " died");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
         }
 
         IDataLoader getDataLoader() {
             return mDataLoader;
         }
 
+        private void unbindAndReportDestroyed() {
+            if (unbind()) {
+                callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
+            }
+        }
+
         void destroy() {
             if (mDataLoader != null) {
                 try {
@@ -244,11 +246,15 @@
                 }
                 mDataLoader = null;
             }
+            unbind();
+        }
+
+        boolean unbind() {
             try {
                 mContext.unbindService(this);
             } catch (Exception ignored) {
             }
-            remove();
+            return remove();
         }
 
         private boolean append() {
@@ -266,12 +272,14 @@
             }
         }
 
-        private void remove() {
+        private boolean remove() {
             synchronized (mServiceConnections) {
                 if (mServiceConnections.get(mId) == this) {
                     mServiceConnections.remove(mId);
+                    return true;
                 }
             }
+            return false;
         }
 
         private void callListener(int status) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 460b2f2..903652a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2086,15 +2086,16 @@
             try {
                 sealLocked();
 
-                // Session that are staged, ready and not multi package will be installed during
-                // this boot. As such, we need populate all the fields for successful installation.
-                if (isMultiPackage()) {
+                // Session that are staged, committed and not multi package will be installed or
+                // restart verification during this boot. As such, we need populate all the fields
+                // for successful installation.
+                if (isMultiPackage() || !isStaged() || !isCommitted()) {
                     return;
                 }
                 final PackageInstallerSession root = hasParentSessionId()
                         ? allSessions.get(getParentSessionId())
                         : this;
-                if (root != null && root.isStagedSessionReady()) {
+                if (root != null) {
                     if (isApexSession()) {
                         validateApexInstallLocked();
                     } else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a4c0655..7da53b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -97,6 +97,10 @@
 import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
 import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
+import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.incremental.IncrementalManager.isIncrementalPath;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
@@ -270,6 +274,7 @@
 import android.os.ParcelableException;
 import android.os.PatternMatcher;
 import android.os.PersistableBundle;
+import android.os.PowerWhitelistManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -2631,7 +2636,8 @@
             // We'll want to include browser possibilities in a few cases
             boolean includeBrowser = false;
 
-            if (!DomainVerificationUtils.isDomainVerificationIntent(intent, matchFlags)) {
+            if (!DomainVerificationUtils.isDomainVerificationIntent(intent, candidates,
+                            matchFlags)) {
                 result.addAll(undefinedList);
                 // Maybe add one for the other profile.
                 if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
@@ -2815,8 +2821,8 @@
                 }
 
                 result.highestApprovalLevel = Math.max(mDomainVerificationManager
-                        .approvalLevelForDomain(ps, intent, flags, riTargetUser.targetUserId),
-                        result.highestApprovalLevel);
+                        .approvalLevelForDomain(ps, intent, resultTargetUser, flags,
+                                riTargetUser.targetUserId), result.highestApprovalLevel);
             }
             if (result != null && result.highestApprovalLevel
                     <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
@@ -3062,8 +3068,8 @@
                     final String packageName = info.activityInfo.packageName;
                     final PackageSetting ps = mSettings.getPackageLPr(packageName);
                     if (ps.getInstantApp(userId)) {
-                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
-                                userId)) {
+                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
+                                instantApps, flags, userId)) {
                             if (DEBUG_INSTANT) {
                                 Slog.v(TAG, "Instant app approved for intent; pkg: "
                                         + packageName);
@@ -3990,8 +3996,8 @@
                 if (ps != null) {
                     // only check domain verification status if the app is not a browser
                     if (!info.handleAllWebDataURI) {
-                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent, flags,
-                                userId)) {
+                        if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
+                                resolvedActivities, flags, userId)) {
                             if (DEBUG_INSTANT) {
                                 Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
                                         + ", approved");
@@ -4629,7 +4635,7 @@
      * computer engine.  This is required because there are no locks taken in
      * the engine itself.
      */
-    private static class ComputerLocked extends ComputerEngine {
+    private static class ComputerLocked extends ComputerEngineLive {
         private final Object mLock;
 
         ComputerLocked(Snapshot args) {
@@ -4637,16 +4643,6 @@
             mLock = mService.mLock;
         }
 
-        protected ComponentName resolveComponentName() {
-            return mService.mResolveComponentName;
-        }
-        protected ActivityInfo instantAppInstallerActivity() {
-            return mService.mInstantAppInstallerActivity;
-        }
-        protected ApplicationInfo androidApplication() {
-            return mService.mAndroidApplication;
-        }
-
         public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
                 String resolvedType, int flags, int userId, int callingUid,
                 String instantAppPkgName) {
@@ -4776,8 +4772,9 @@
     }
 
 
-    // Compute read-only functions, based on live data.
-    private final Computer mLiveComputer;
+    // Compute read-only functions, based on live data.  This attribute may be modified multiple
+    // times during the PackageManagerService constructor but it should not be modified thereafter.
+    private Computer mLiveComputer;
     // A lock-free cache for frequently called functions.
     private volatile Computer mSnapshotComputer;
     // If true, the snapshot is invalid (stale).  The attribute is static since it may be
@@ -5552,7 +5549,8 @@
                             packageName /*targetPackage*/,
                             null /*finishedReceiver*/, updateUserIds, instantUserIds,
                             null /*broadcastAllowList*/,
-                            getTemporaryAppWhitelistBroadcastOptions().toBundle());
+                            getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
+                                    .toBundle());
                 } else if (launchedForRestore && !res.pkg.isSystem()) {
                     // First-install and we did a restore, so we're responsible for the
                     // first-launch broadcast.
@@ -6395,8 +6393,9 @@
         // constructor.
         mSnapshotEnabled = SNAPSHOT_ENABLED;
         sSnapshotCorked = true;
+        sSnapshotInvalid = true;
         mLiveComputer = createLiveComputer();
-        mSnapshotComputer = mLiveComputer;
+        mSnapshotComputer = null;
         registerObserver();
 
         // CHECKSTYLE:OFF IndentationCheck
@@ -7075,6 +7074,10 @@
                         BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
                         SystemClock.uptimeMillis() - startTime);
             }
+
+            // Rebild the live computer since some attributes have been rebuilt.
+            mLiveComputer = createLiveComputer();
+
         } // synchronized (mLock)
         } // synchronized (mInstallLock)
         // CHECKSTYLE:ON IndentationCheck
@@ -9573,7 +9576,7 @@
                         final String packageName = ri.activityInfo.packageName;
                         final PackageSetting ps = mSettings.getPackageLPr(packageName);
                         if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps,
-                                intent, flags, userId)) {
+                                intent, query, flags, userId)) {
                             return ri;
                         }
                     }
@@ -9630,10 +9633,10 @@
      */
     private static boolean hasAnyDomainApproval(
             @NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
-            @NonNull Intent intent, @PackageManager.ResolveInfoFlags int resolveInfoFlags,
-            @UserIdInt int userId) {
-        return manager.approvalLevelForDomain(pkgSetting, intent, resolveInfoFlags, userId)
-                > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+            @NonNull Intent intent, @NonNull List<ResolveInfo> candidates,
+            @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
+        return manager.approvalLevelForDomain(pkgSetting, intent, candidates, resolveInfoFlags,
+                userId) > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
     }
 
     /**
@@ -11631,9 +11634,17 @@
                 healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
                 healthCheckParams.unhealthyMonitoringMs =
                         INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
+                // Continue monitoring health and loading progress of active incremental packages
                 mIncrementalManager.registerHealthListener(parsedPackage.getPath(),
                         healthCheckParams,
                         new IncrementalHealthListener(parsedPackage.getPackageName()));
+                final IncrementalStatesCallback incrementalStatesCallback =
+                        new IncrementalStatesCallback(parsedPackage.getPackageName(),
+                                UserHandle.getUid(UserHandle.ALL, pkgSetting.appId),
+                                getInstalledUsers(pkgSetting, UserHandle.USER_ALL));
+                pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
+                mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
+                        new IncrementalProgressListener(parsedPackage.getPackageName()));
             }
         }
         return scanResult.pkgSetting.pkg;
@@ -15193,7 +15204,8 @@
                 lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
             }
             final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
-            final BroadcastOptions bOptions = getTemporaryAppWhitelistBroadcastOptions();
+            final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
+                    REASON_LOCKED_BOOT_COMPLETED);
             am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
                     requiredPermissions, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(),
                     false, false,
@@ -17582,7 +17594,9 @@
                         mInjector.getLocalService(DeviceIdleInternal.class);
                 final long idleDuration = getVerificationTimeout();
                 final BroadcastOptions options = BroadcastOptions.makeBasic();
-                options.setTemporaryAppWhitelistDuration(idleDuration);
+                options.setTemporaryAppAllowlist(idleDuration,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                        REASON_PACKAGE_VERIFIER, "");
 
                 /*
                  * If any sufficient verifiers were listed in the package
@@ -17598,7 +17612,8 @@
                             final ComponentName verifierComponent = sufficientVerifiers.get(i);
                             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                     verifierComponent.getPackageName(), idleDuration,
-                                    verifierUser.getIdentifier(), false, "package verifier");
+                                    verifierUser.getIdentifier(), false,
+                                    REASON_PACKAGE_VERIFIER,"package verifier");
 
                             final Intent sufficientIntent = new Intent(verification);
                             sufficientIntent.setComponent(verifierComponent);
@@ -17620,7 +17635,8 @@
                     verification.setComponent(requiredVerifierComponent);
                     idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                             mRequiredVerifierPackage, idleDuration,
-                            verifierUser.getIdentifier(), false, "package verifier");
+                            verifierUser.getIdentifier(), false,
+                            REASON_PACKAGE_VERIFIER, "package verifier");
                     mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                             android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                             /* appOp= */ AppOpsManager.OP_NONE,
@@ -17977,7 +17993,9 @@
             try {
                 makeDirRecursive(afterCodeFile.getParentFile(), 0775);
                 if (onIncremental) {
-                    mIncrementalManager.renameCodePath(beforeCodeFile, afterCodeFile);
+                    // Just link files here. The stage dir will be removed when the installation
+                    // session is completed.
+                    mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
                 } else {
                     Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
                 }
@@ -17986,7 +18004,6 @@
                 return false;
             }
 
-            //TODO(b/136132412): enable selinux restorecon for incremental directories
             if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
                 Slog.w(TAG, "Failed to restorecon");
                 return false;
@@ -19412,6 +19429,8 @@
             mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
             // Unregister health listener as it will always be healthy from now
             mIncrementalManager.unregisterHealthListener(codePath);
+            // Make sure the information is preserved
+            scheduleWriteSettingsLocked();
         }
 
         @Override
@@ -19474,11 +19493,11 @@
             final PackageSetting ps;
             synchronized (mLock) {
                 ps = mSettings.getPackageLPr(mPackageName);
+                if (ps == null) {
+                    return;
+                }
+                ps.setLoadingProgress(progress);
             }
-            if (ps == null) {
-                return;
-            }
-            ps.setLoadingProgress(progress);
         }
     }
 
@@ -20082,7 +20101,7 @@
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
-                        "Error deriving application ABI");
+                        "Error deriving application ABI: " + pme.getMessage());
             }
         }
 
@@ -20971,7 +20990,7 @@
                     extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
             packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
                     removedPackage, null, null, null, null /* broadcastAllowList */,
-                    getTemporaryAppWhitelistBroadcastOptions().toBundle());
+                    getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
             if (installerPackageName != null) {
                 packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                         removedPackage, extras, 0 /*flags*/,
@@ -26110,6 +26129,11 @@
             return PackageManagerService.this.hasSigningCertificate(
                 packageName, certificate, CERT_INPUT_SHA256);
         }
+
+        @Override
+        public boolean hasSystemFeature(String featureName, int version) {
+            return PackageManagerService.this.hasSystemFeature(featureName, version);
+        }
     }
 
     private AndroidPackage getPackage(String packageName) {
@@ -27818,7 +27842,8 @@
         return result.toArray(new PerUidReadTimeouts[result.size()]);
     }
 
-    static @NonNull BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
+    static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+            @PowerWhitelistManager.ReasonCode int reasonCode) {
         long duration = 10_000;
         final ActivityManagerInternal amInternal =
                 LocalServices.getService(ActivityManagerInternal.class);
@@ -27826,9 +27851,9 @@
             duration = amInternal.getBootTimeTempAllowListDuration();
         }
         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
-        bOptions.setTemporaryAppWhitelistDuration(
-                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                duration);
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                reasonCode, "");
         return bOptions;
     }
 
diff --git a/services/core/java/com/android/server/pm/SettingsXml.java b/services/core/java/com/android/server/pm/SettingsXml.java
index ec643f5..c53fef7 100644
--- a/services/core/java/com/android/server/pm/SettingsXml.java
+++ b/services/core/java/com/android/server/pm/SettingsXml.java
@@ -83,7 +83,7 @@
         @Override
         public void close() throws IOException {
             mWriteSection.closeCompletely();
-            mXmlSerializer.endDocument();
+            mXmlSerializer.flush();
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
index 1c5f0a7..f411c98 100644
--- a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
+++ b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
@@ -280,7 +280,8 @@
                     IoUtils.closeQuietly(out);
                 }
 
-                shortcut.setBitmapPath(file.getAbsolutePath());
+                final String path = file.getAbsolutePath();
+                mService.postValue(shortcut, si -> si.setBitmapPath(path));
 
             } catch (IOException | RuntimeException e) {
                 Slog.e(ShortcutService.TAG, "Unable to write bitmap to file", e);
@@ -295,12 +296,14 @@
                 Slog.d(TAG, "Saved bitmap.");
             }
             if (shortcut != null) {
-                if (shortcut.getBitmapPath() == null) {
-                    removeIcon(shortcut);
-                }
+                mService.postValue(shortcut, si -> {
+                    if (si.getBitmapPath() == null) {
+                        removeIcon(si);
+                    }
 
-                // Whatever happened, remove this flag.
-                shortcut.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
+                    // Whatever happened, remove this flag.
+                    si.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
+                });
             }
         }
         return true;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index a604afc..302e657 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -223,12 +223,14 @@
         // - Disable if needed.
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             ShortcutInfo si = mShortcuts.valueAt(i);
-            si.clearFlags(ShortcutInfo.FLAG_SHADOW);
+            mutateShortcut(si.getId(), si, shortcut -> {
+                shortcut.clearFlags(ShortcutInfo.FLAG_SHADOW);
 
-            si.setDisabledReason(restoreBlockReason);
-            if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
-                si.addFlags(ShortcutInfo.FLAG_DISABLED);
-            }
+                shortcut.setDisabledReason(restoreBlockReason);
+                if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+                    shortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
+                }
+            });
         }
         // Because some launchers may not have been restored (e.g. allowBackup=false),
         // we need to re-calculate the pinned shortcuts.
@@ -460,9 +462,11 @@
             if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) {
                 changed = true;
 
-                si.setTimestamp(now);
-                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
-                si.setRank(0); // It may still be pinned, so clear the rank.
+                mutateShortcut(si.getId(), si, shortcut -> {
+                    shortcut.setTimestamp(now);
+                    shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+                    shortcut.setRank(0); // It may still be pinned, so clear the rank.
+                });
             }
         }
         if (changed) {
@@ -506,7 +510,7 @@
     public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
         final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
         if (shortcut != null) {
-            shortcut.clearFlags(ShortcutInfo.FLAG_CACHED_ALL);
+            mutateShortcut(shortcutId, null, si -> si.clearFlags(ShortcutInfo.FLAG_CACHED_ALL));
         }
         return deleteOrDisableWithId(
                 shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
@@ -527,15 +531,16 @@
                 overrideImmutable, ignoreInvisible, disabledReason);
 
         // If disabled id still exists, it is pinned and we need to update the disabled message.
-        final ShortcutInfo disabled = mShortcuts.get(shortcutId);
-        if (disabled != null) {
-            if (disabledMessage != null) {
-                disabled.setDisabledMessage(disabledMessage);
-            } else if (disabledMessageResId != 0) {
-                disabled.setDisabledMessageResId(disabledMessageResId);
-                mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
+        mutateShortcut(shortcutId, null, disabled -> {
+            if (disabled != null) {
+                if (disabledMessage != null) {
+                    disabled.setDisabledMessage(disabledMessage);
+                } else if (disabledMessageResId != 0) {
+                    disabled.setDisabledMessageResId(disabledMessageResId);
+                    mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
+                }
             }
-        }
+        });
 
         return deleted;
     }
@@ -557,21 +562,23 @@
         }
         if (oldShortcut.isPinned() || oldShortcut.isCached()) {
 
-            oldShortcut.setRank(0);
-            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
-            if (disable) {
-                oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
-                // Do not overwrite the disabled reason if one is alreay set.
-                if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
-                    oldShortcut.setDisabledReason(disabledReason);
+            mutateShortcut(oldShortcut.getId(), oldShortcut, si -> {
+                si.setRank(0);
+                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
+                if (disable) {
+                    si.addFlags(ShortcutInfo.FLAG_DISABLED);
+                    // Do not overwrite the disabled reason if one is alreay set.
+                    if (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+                        si.setDisabledReason(disabledReason);
+                    }
                 }
-            }
-            oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
+                si.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
 
-            // See ShortcutRequestPinProcessor.directPinShortcut().
-            if (mShortcutUser.mService.isDummyMainActivity(oldShortcut.getActivity())) {
-                oldShortcut.setActivity(null);
-            }
+                // See ShortcutRequestPinProcessor.directPinShortcut().
+                if (mShortcutUser.mService.isDummyMainActivity(si.getActivity())) {
+                    si.setActivity(null);
+                }
+            });
 
             return null;
         } else {
@@ -581,12 +588,11 @@
     }
 
     public void enableWithId(@NonNull String shortcutId) {
-        final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
-        if (shortcut != null) {
-            ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true);
-            shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
-            shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
-        }
+        mutateShortcut(shortcutId, null, si -> {
+            ensureNotImmutable(si, /*ignoreInvisible=*/ true);
+            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
+            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+        });
     }
 
     public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) {
@@ -609,22 +615,25 @@
      * <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
      */
     public void refreshPinnedFlags() {
-        // First, un-pin all shortcuts
-        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
-            mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
+        // TODO: rewrite this function with proper query (i.e. fetch only pinned shortcuts and
+        //  unpin if it's no longer pinned by any launcher and vice versa)
+        final List<ShortcutInfo> shortcuts = new ArrayList<>(mShortcuts.values());
+        final Map<String, ShortcutInfo> shortcutMap = new ArrayMap<>(shortcuts.size());
+        for (ShortcutInfo si : shortcuts) {
+            shortcutMap.put(si.getId(), si);
         }
+        final Set<String> pinnedShortcuts = new ArraySet<>();
 
-        // Then, for the pinned set for each launcher, set the pin flag one by one.
+        // First, for the pinned set for each launcher, keep track of their id one by one.
         mShortcutUser.forAllLaunchers(launcherShortcuts -> {
             final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
                     getPackageName(), getPackageUserId());
-
             if (pinned == null || pinned.size() == 0) {
                 return;
             }
             for (int i = pinned.size() - 1; i >= 0; i--) {
                 final String id = pinned.valueAt(i);
-                final ShortcutInfo si = mShortcuts.get(id);
+                final ShortcutInfo si = shortcutMap.get(id);
                 if (si == null) {
                     // This happens if a launcher pinned shortcuts from this package, then backup&
                     // restored, but this package doesn't allow backing up.
@@ -632,9 +641,21 @@
                     // That's fine, when the launcher is restored, we'll fix it.
                     continue;
                 }
-                si.addFlags(ShortcutInfo.FLAG_PINNED);
+                pinnedShortcuts.add(si.getId());
             }
         });
+        // Then, update the pinned state if necessary
+        for (int i = shortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = shortcuts.get(i);
+            if (pinnedShortcuts.contains(si.getId()) && !si.isPinned()) {
+                mutateShortcut(si.getId(), si,
+                        shortcut -> shortcut.addFlags(ShortcutInfo.FLAG_PINNED));
+            }
+            if (!pinnedShortcuts.contains(si.getId()) && si.isPinned()) {
+                mutateShortcut(si.getId(), si, shortcut ->
+                        shortcut.clearFlags(ShortcutInfo.FLAG_PINNED));
+            }
+        }
 
         // Lastly, remove the ones that are no longer pinned, cached nor dynamic.
         removeOrphans();
@@ -1034,8 +1055,10 @@
                 continue;
             }
             Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId()));
-            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
-            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+            mutateShortcut(si.getId(), si, shortcut -> {
+                shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
+                shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+            });
         }
 
         // For existing shortcuts, update timestamps if they have any resources.
@@ -1065,21 +1088,24 @@
                 }
 
                 if (si.hasAnyResources()) {
-                    if (!si.isOriginallyFromManifest()) {
+                    if (publisherRes == null) {
+                        publisherRes = getPackageResources();
                         if (publisherRes == null) {
-                            publisherRes = getPackageResources();
-                            if (publisherRes == null) {
-                                break; // Resources couldn't be loaded.
-                            }
+                            break; // Resources couldn't be loaded.
+                        }
+                    }
+
+                    final Resources res = publisherRes;
+                    mutateShortcut(si.getId(), si, shortcut -> {
+                        if (!shortcut.isOriginallyFromManifest()) {
+                            shortcut.lookupAndFillInResourceIds(res);
                         }
 
-                        // TODO: update resource strings in AppSearch
                         // If this shortcut is not from a manifest, then update all resource IDs
                         // from resource names.  (We don't allow resource strings for
                         // non-manifest at the moment, but icons can still be resources.)
-                        si.lookupAndFillInResourceIds(publisherRes);
-                    }
-                    si.setTimestamp(s.injectCurrentTimeMillis());
+                        shortcut.setTimestamp(s.injectCurrentTimeMillis());
+                    });
                 }
             }
         }
@@ -1382,8 +1408,11 @@
                     }
                 }
 
-                si.resolveResourceStrings(publisherRes);
-                si.setTimestamp(s.injectCurrentTimeMillis());
+                final Resources res = publisherRes;
+                mutateShortcut(si.getId(), si, shortcut -> {
+                    shortcut.resolveResourceStrings(res);
+                    shortcut.setTimestamp(s.injectCurrentTimeMillis());
+                });
 
                 if (changedShortcuts == null) {
                     changedShortcuts = new ArrayList<>(1);
@@ -1400,7 +1429,7 @@
     public void clearAllImplicitRanks() {
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-            si.clearImplicitRankAndRankChangedFlag();
+            mutateShortcut(si.getId(), si, ShortcutInfo::clearImplicitRankAndRankChangedFlag);
         }
     }
 
@@ -1445,8 +1474,10 @@
             final ShortcutInfo si = mShortcuts.valueAt(i);
             if (si.isFloating()) {
                 if (si.getRank() != 0) {
-                    si.setTimestamp(now);
-                    si.setRank(0);
+                    mutateShortcut(si.getId(), si, shortcut -> {
+                        shortcut.setTimestamp(now);
+                        shortcut.setRank(0);
+                    });
                 }
             }
         }
@@ -1479,8 +1510,10 @@
                 }
                 final int thisRank = rank++;
                 if (si.getRank() != thisRank) {
-                    si.setTimestamp(now);
-                    si.setRank(thisRank);
+                    mutateShortcut(si.getId(), si, shortcut -> {
+                        shortcut.setTimestamp(now);
+                        shortcut.setRank(thisRank);
+                    });
                 }
             }
         }
@@ -2172,6 +2205,32 @@
         resetAppSearch(null);
     }
 
+    void mutateShortcut(@NonNull final String id, @Nullable final ShortcutInfo shortcut,
+            @NonNull final Consumer<ShortcutInfo> transform) {
+        Objects.requireNonNull(id);
+        Objects.requireNonNull(transform);
+        synchronized (mLock) {
+            if (shortcut != null) {
+                transform.accept(shortcut);
+            } else {
+                transform.accept(findShortcutById(id));
+            }
+            // TODO: Load ShortcutInfo from AppSearch, apply transformation logic and save
+        }
+    }
+
+    /**
+     * Removes shortcuts from AppSearch.
+     */
+    void removeShortcuts() {
+    }
+
+    /**
+     * Merge/replace shortcuts parsed from xml file.
+     */
+    void restoreParsedShortcuts(final boolean replace) {
+    }
+
     private boolean verifyRanksSequential(List<ShortcutInfo> list) {
         boolean failed = false;
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 209a143..a377f1c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -362,6 +362,7 @@
     private List<Integer> mDirtyUserIds = new ArrayList<>();
 
     private final AtomicBoolean mBootCompleted = new AtomicBoolean();
+    private final AtomicBoolean mShutdown = new AtomicBoolean();
 
     /**
      * Note we use a fine-grained lock for {@link #mUnlockedUsers} due to b/64303666.
@@ -498,6 +499,12 @@
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL,
                 localeFilter, null, mHandler);
 
+        IntentFilter shutdownFilter = new IntentFilter();
+        shutdownFilter.addAction(Intent.ACTION_SHUTDOWN);
+        shutdownFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        mContext.registerReceiverAsUser(mShutdownReceiver, UserHandle.SYSTEM,
+                shutdownFilter, null, mHandler);
+
         injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
                 | ActivityManager.UID_OBSERVER_GONE);
 
@@ -662,7 +669,7 @@
     /** lifecycle event */
     void handleUnlockUser(int userId) {
         if (DEBUG) {
-        Slog.d(TAG, "handleUnlockUser: user=" + userId);
+            Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mUnlockedUsers) {
             mUnlockedUsers.put(userId, true);
@@ -1162,6 +1169,9 @@
         if (DEBUG) {
             Slog.d(TAG, "saveDirtyInfo");
         }
+        if (mShutdown.get()) {
+            return;
+        }
         try {
             synchronized (mLock) {
                 for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
@@ -1179,6 +1189,14 @@
         }
     }
 
+    void postValue(@NonNull final ShortcutInfo shortcutInfo,
+            @NonNull final Consumer<ShortcutInfo> cb) {
+        final String pkg = shortcutInfo.getPackage();
+        final int userId = shortcutInfo.getUserId();
+        final String id = shortcutInfo.getId();
+        getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
+    }
+
     /** Return the last reset time. */
     @GuardedBy("mLock")
     long getLastResetTimeLocked() {
@@ -1566,7 +1584,6 @@
      * resource-based strings.
      */
     void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
-        // TODO: update resource names in AppSearch
         final Resources publisherRes = injectGetResourcesForApplicationAsUser(
                 si.getPackage(), si.getUserId());
         if (publisherRes != null) {
@@ -1947,7 +1964,7 @@
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
                 injectBinderCallingPid(), injectBinderCallingUid());
 
-        List<ShortcutInfo> changedShortcuts = null;
+        final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1);
 
         synchronized (mLock) {
             throwIfUserLockedL(userId);
@@ -1975,59 +1992,57 @@
                 final ShortcutInfo source = newShortcuts.get(i);
                 fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
 
-                final ShortcutInfo target = ps.findShortcutById(source.getId());
+                ps.mutateShortcut(source.getId(), null, target -> {
+                    // Invisible shortcuts can't be updated.
+                    if (target == null || !target.isVisibleToPublisher()) {
+                        return;
+                    }
 
-                // Invisible shortcuts can't be updated.
-                if (target == null || !target.isVisibleToPublisher()) {
-                    continue;
-                }
+                    if (target.isEnabled() != source.isEnabled()) {
+                        Slog.w(TAG,
+                                "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
+                    }
 
-                if (target.isEnabled() != source.isEnabled()) {
-                    Slog.w(TAG,
-                            "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
-                }
+                    if (target.isLongLived() != source.isLongLived()) {
+                        Slog.w(TAG,
+                                "ShortcutInfo.longLived cannot be changed with updateShortcuts()");
+                    }
 
-                if (target.isLongLived() != source.isLongLived()) {
-                    Slog.w(TAG,
-                            "ShortcutInfo.longLived cannot be changed with updateShortcuts()");
-                }
+                    // When updating the rank, we need to insert between existing ranks, so set
+                    // this setRankChanged, and also copy the implicit rank fo adjustRanks().
+                    if (source.hasRank()) {
+                        target.setRankChanged();
+                        target.setImplicitRank(source.getImplicitRank());
+                    }
 
-                // When updating the rank, we need to insert between existing ranks, so set
-                // this setRankChanged, and also copy the implicit rank fo adjustRanks().
-                if (source.hasRank()) {
-                    target.setRankChanged();
-                    target.setImplicitRank(source.getImplicitRank());
-                }
+                    final boolean replacingIcon = (source.getIcon() != null);
+                    if (replacingIcon) {
+                        removeIconLocked(target);
+                    }
 
-                final boolean replacingIcon = (source.getIcon() != null);
-                if (replacingIcon) {
-                    removeIconLocked(target);
-                }
+                    // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
+                    target.copyNonNullFieldsFrom(source);
+                    target.setTimestamp(injectCurrentTimeMillis());
 
-                // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
-                target.copyNonNullFieldsFrom(source);
-                target.setTimestamp(injectCurrentTimeMillis());
+                    if (replacingIcon) {
+                        saveIconAndFixUpShortcutLocked(target);
+                    }
 
-                if (replacingIcon) {
-                    saveIconAndFixUpShortcutLocked(target);
-                }
+                    // When we're updating any resource related fields, re-extract the res names and
+                    // the values.
+                    if (replacingIcon || source.hasStringResources()) {
+                        fixUpShortcutResourceNamesAndValues(target);
+                    }
 
-                // When we're updating any resource related fields, re-extract the res names and
-                // the values.
-                if (replacingIcon || source.hasStringResources()) {
-                    fixUpShortcutResourceNamesAndValues(target);
-                }
-
-                if (changedShortcuts == null) {
-                    changedShortcuts = new ArrayList<>(1);
-                }
-                changedShortcuts.add(target);
+                    changedShortcuts.add(target);
+                });
             }
 
             // Lastly, adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId, changedShortcuts, null);
+        packageShortcutsChanged(packageName, userId,
+                changedShortcuts.isEmpty() ? null : changedShortcuts, null);
 
         verifyStates();
 
@@ -3114,7 +3129,8 @@
 
                     if (doCache) {
                         if (si.isLongLived()) {
-                            si.addFlags(cacheFlags);
+                            sp.mutateShortcut(si.getId(), si,
+                                    shortcut -> shortcut.addFlags(cacheFlags));
                             if (changedShortcuts == null) {
                                 changedShortcuts = new ArrayList<>(1);
                             }
@@ -3125,7 +3141,8 @@
                         }
                     } else {
                         ShortcutInfo removed = null;
-                        si.clearFlags(cacheFlags);
+                        sp.mutateShortcut(si.getId(), si, shortcut ->
+                                shortcut.clearFlags(cacheFlags));
                         if (!si.isDynamic() && !si.isCached()) {
                             removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
                         }
@@ -3487,6 +3504,22 @@
         }
     };
 
+    private final BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Since it cleans up the shortcut directory and rewrite the ShortcutPackageItems
+            // in odrder during saveToXml(), it could lead to shortcuts missing when shutdown.
+            // We need it so that it can finish up saving before shutdown.
+            synchronized (mLock) {
+                if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
+                    mHandler.removeCallbacks(mSaveDirtyInfoRunner);
+                    saveDirtyInfo();
+                }
+                mShutdown.set(true);
+            }
+        }
+    };
+
     /**
      * Called when a user is unlocked.
      * - Check all known packages still exist, and otherwise perform cleanup.
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 6cbc47f..ec784d0 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -185,6 +185,9 @@
     public ShortcutPackage removePackage(@NonNull String packageName) {
         final ShortcutPackage removed = mPackages.remove(packageName);
 
+        if (removed != null) {
+            removed.removeShortcuts();
+        }
         mService.cleanupBitmapsForPackage(mUserId, packageName);
 
         return removed;
@@ -330,7 +333,10 @@
 
         if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
             if (isNewApp) {
-                mPackages.remove(packageName);
+                final ShortcutPackage sp = mPackages.remove(packageName);
+                if (sp != null) {
+                    sp.removeShortcuts();
+                }
             }
         }
     }
@@ -454,6 +460,7 @@
                         case ShortcutPackage.TAG_ROOT: {
                             final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
                                     s, ret, parser, fromBackup);
+                            shortcuts.restoreParsedShortcuts(false);
 
                             // Don't use addShortcut(), we don't need to save the icon.
                             ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
@@ -488,6 +495,7 @@
                 final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
                 if (sp != null) {
                     ret.mPackages.put(sp.getPackageName(), sp);
+                    sp.restoreParsedShortcuts(false);
                 }
             });
 
@@ -570,6 +578,7 @@
                 Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
                         + " Existing non-manifeset shortcuts will be overwritten.");
             }
+            sp.restoreParsedShortcuts(true);
             addPackage(sp);
             restoredPackages[0]++;
             restoredShortcuts[0] += sp.getShortcutCount();
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index c17d2e4..eb2de60 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -63,8 +63,13 @@
      */
     public interface UserLifecycleListener {
 
-        /** Called when a new user is created. */
-        default void onUserCreated(UserInfo user) {}
+        /**
+         * Called when a new user is created.
+         *
+         * @param user new user.
+         * @param token token passed to the method that created the user.
+         */
+        default void onUserCreated(UserInfo user, @Nullable Object token) {}
 
         /** Called when an existing user is removed. */
         default void onUserRemoved(UserInfo user) {}
@@ -179,10 +184,12 @@
      * {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}
      *
      * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
-     * createAndManageUser is called by the device owner.
+     * createAndManageUser is called by the device owner; it uses {@code token} to block until
+     * the user is created (as it will be passed back to it through
+     * {@link UserLifecycleListener#onUserCreated(UserInfo, Object)});
      */
     public abstract UserInfo createUserEvenWhenDisallowed(String name, String userType,
-            int flags, String[] disallowedPackages)
+            int flags, String[] disallowedPackages, @Nullable Object token)
             throws UserManager.CheckedUserOperationException;
 
     /**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4fc9b0b..871576e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3323,7 +3323,7 @@
         checkManageOrCreateUsersPermission(flags);
         try {
             return createUserInternalUnchecked(name, userType, flags, userId,
-                    /* preCreate= */ false, disallowedPackages);
+                    /* preCreate= */ false, disallowedPackages, /* token= */ null);
         } catch (UserManager.CheckedUserOperationException e) {
             throw e.toServiceSpecificException();
         }
@@ -3356,7 +3356,7 @@
         try {
             return createUserInternalUnchecked(/* name= */ null, userType, flags,
                     /* parentId= */ UserHandle.USER_NULL, /* preCreate= */ true,
-                    /* disallowedPackages= */ null);
+                    /* disallowedPackages= */ null, /* token= */ null);
         } catch (UserManager.CheckedUserOperationException e) {
             throw e.toServiceSpecificException();
         }
@@ -3372,12 +3372,13 @@
         enforceUserRestriction(restriction, UserHandle.getCallingUserId(),
                 "Cannot add user");
         return createUserInternalUnchecked(name, userType, flags, parentId,
-                /* preCreate= */ false, disallowedPackages);
+                /* preCreate= */ false, disallowedPackages, /* token= */ null);
     }
 
     private UserInfo createUserInternalUnchecked(@Nullable String name,
             @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
-            boolean preCreate, @Nullable String[] disallowedPackages)
+            boolean preCreate, @Nullable String[] disallowedPackages,
+            @Nullable Object token)
             throws UserManager.CheckedUserOperationException {
         final int nextProbableUserId = getNextAvailableId();
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
@@ -3386,7 +3387,7 @@
         UserInfo newUser = null;
         try {
             newUser = createUserInternalUncheckedNoTracing(name, userType, flags, parentId,
-                        preCreate, disallowedPackages, t);
+                        preCreate, disallowedPackages, t, token);
             return newUser;
         } finally {
             logUserCreateJourneyFinish(sessionId, nextProbableUserId, newUser != null);
@@ -3397,7 +3398,8 @@
     private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name,
             @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
             boolean preCreate, @Nullable String[] disallowedPackages,
-            @NonNull TimingsTraceAndSlog t) throws UserManager.CheckedUserOperationException {
+            @NonNull TimingsTraceAndSlog t, @Nullable Object token)
+                    throws UserManager.CheckedUserOperationException {
         final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
         if (userTypeDetails == null) {
             Slog.e(LOG_TAG, "Cannot create user of invalid user type: " + userType);
@@ -3423,7 +3425,8 @@
 
         // Try to use a pre-created user (if available).
         if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
-            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name);
+            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name,
+                    token);
             if (preCreatedUser != null) {
                 return preCreatedUser;
             }
@@ -3602,7 +3605,7 @@
                     Slog.w(LOG_TAG, "could not start pre-created user " + userId, e);
                 }
             } else {
-                dispatchUserAdded(userInfo);
+                dispatchUserAdded(userInfo, token);
             }
 
         } finally {
@@ -3702,7 +3705,7 @@
      * @return the converted user, or {@code null} if no pre-created user could be converted.
      */
     private @Nullable UserInfo convertPreCreatedUserIfPossible(String userType,
-            @UserInfoFlag int flags, String name) {
+            @UserInfoFlag int flags, String name, @Nullable Object token) {
         final UserData preCreatedUserData;
         synchronized (mUsersLock) {
             preCreatedUserData = getPreCreatedUserLU(userType);
@@ -3740,7 +3743,7 @@
         }
         updateUserIds();
         mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true);
-        dispatchUserAdded(preCreatedUser);
+        dispatchUserAdded(preCreatedUser, token);
         return preCreatedUser;
     }
 
@@ -3772,11 +3775,11 @@
         return (now > EPOCH_PLUS_30_YEARS) ? now : 0;
     }
 
-    private void dispatchUserAdded(@NonNull UserInfo userInfo) {
+    private void dispatchUserAdded(@NonNull UserInfo userInfo, @Nullable Object token) {
         // Notify internal listeners first...
         synchronized (mUserLifecycleListeners) {
             for (int i = 0; i < mUserLifecycleListeners.size(); i++) {
-                mUserLifecycleListeners.get(i).onUserCreated(userInfo);
+                mUserLifecycleListeners.get(i).onUserCreated(userInfo, token);
             }
         }
 
@@ -5381,10 +5384,10 @@
 
         @Override
         public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
-                @UserInfoFlag int flags, String[] disallowedPackages)
+                @UserInfoFlag int flags, String[] disallowedPackages, @Nullable Object token)
                 throws UserManager.CheckedUserOperationException {
             return createUserInternalUnchecked(name, userType, flags,
-                    UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages);
+                    UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages, token);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index e05ef48..8c1a90c 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,9 +1,7 @@
-zhanghai@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
 per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
 per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
-per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
 per-file DefaultPermissionGrantPolicy.java = toddke@google.com
 per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
 per-file DefaultPermissionGrantPolicy.java = patb@google.com
-per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
-per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index e3cf67c..bf2b3c7 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -84,7 +84,7 @@
 
     @NonNull
     public ArraySet<String> collectAllWebDomains(@NonNull AndroidPackage pkg) {
-        return collectDomains(pkg, false);
+        return collectDomains(pkg, false /* checkAutoVerify */, true /* valid */);
     }
 
     /**
@@ -92,20 +92,29 @@
      * IntentFilter#getAutoVerify()} == true.
      */
     @NonNull
-    public ArraySet<String> collectAutoVerifyDomains(@NonNull AndroidPackage pkg) {
-        return collectDomains(pkg, true);
+    public ArraySet<String> collectValidAutoVerifyDomains(@NonNull AndroidPackage pkg) {
+        return collectDomains(pkg, true /* checkAutoVerify */, true /* valid */);
+    }
+
+    /**
+     * Returns all the domains that are configured to be auto verified, but aren't actually valid
+     * HTTP domains, per {@link #DOMAIN_NAME_WITH_WILDCARD}.
+     */
+    @NonNull
+    public ArraySet<String> collectInvalidAutoVerifyDomains(@NonNull AndroidPackage pkg) {
+        return collectDomains(pkg, true /* checkAutoVerify */, false /* valid */);
     }
 
     @NonNull
     private ArraySet<String> collectDomains(@NonNull AndroidPackage pkg,
-            boolean checkAutoVerify) {
+            boolean checkAutoVerify, boolean valid) {
         boolean restrictDomains =
                 DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, RESTRICT_DOMAINS);
 
         if (restrictDomains) {
-            return collectDomainsInternal(pkg, checkAutoVerify);
+            return collectDomainsInternal(pkg, checkAutoVerify, valid);
         } else {
-            return collectDomainsLegacy(pkg, checkAutoVerify);
+            return collectDomainsLegacy(pkg, checkAutoVerify, valid);
         }
     }
 
@@ -113,10 +122,10 @@
      * @see #RESTRICT_DOMAINS
      */
     private ArraySet<String> collectDomainsLegacy(@NonNull AndroidPackage pkg,
-            boolean checkAutoVerify) {
+            boolean checkAutoVerify, boolean valid) {
         if (!checkAutoVerify) {
             // Per-domain user selection state doesn't have a V1 equivalent on S, so just use V2
-            return collectDomainsInternal(pkg, false);
+            return collectDomainsInternal(pkg, false /* checkAutoVerify */, true /* valid */);
         }
 
         List<ParsedActivity> activities = pkg.getActivities();
@@ -157,7 +166,7 @@
                     int authorityCount = intent.countDataAuthorities();
                     for (int index = 0; index < authorityCount; index++) {
                         String host = intent.getDataAuthority(index).getHost();
-                        if (isValidHost(host)) {
+                        if (isValidHost(host) == valid) {
                             totalSize += byteSizeOf(host);
                             underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
                             domains.add(host);
@@ -174,7 +183,7 @@
      * @see #RESTRICT_DOMAINS
      */
     private ArraySet<String> collectDomainsInternal(@NonNull AndroidPackage pkg,
-            boolean checkAutoVerify) {
+            boolean checkAutoVerify, boolean valid) {
         ArraySet<String> domains = new ArraySet<>();
         int totalSize = 0;
         boolean underMaxSize = true;
@@ -214,7 +223,7 @@
                 int authorityCount = intent.countDataAuthorities();
                 for (int index = 0; index < authorityCount && underMaxSize; index++) {
                     String host = intent.getDataAuthority(index).getHost();
-                    if (isValidHost(host)) {
+                    if (isValidHost(host) == valid) {
                         totalSize += byteSizeOf(host);
                         underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
                         domains.add(host);
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index b3108c5..b61fd8d 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -33,9 +33,9 @@
 import com.android.internal.util.CollectionUtils;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
 import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
 
 import java.util.Arrays;
 import java.util.function.Function;
@@ -107,7 +107,7 @@
         reusedMap.clear();
         reusedMap.putAll(pkgState.getStateMap());
 
-        ArraySet<String> declaredDomains = mCollector.collectAutoVerifyDomains(pkg);
+        ArraySet<String> declaredDomains = mCollector.collectValidAutoVerifyDomains(pkg);
         int declaredSize = declaredDomains.size();
         for (int declaredIndex = 0; declaredIndex < declaredSize; declaredIndex++) {
             String domain = declaredDomains.valueAt(declaredIndex);
@@ -132,6 +132,17 @@
             }
 
             writer.increaseIndent();
+            final ArraySet<String> invalidDomains = mCollector.collectInvalidAutoVerifyDomains(pkg);
+            if (!invalidDomains.isEmpty()) {
+                writer.println("Invalid autoVerify domains:");
+                writer.increaseIndent();
+                int size = invalidDomains.size();
+                for (int index = 0; index < size; index++) {
+                    writer.println(invalidDomains.valueAt(index));
+                }
+                writer.decreaseIndent();
+            }
+
             writer.println("Domain verification state:");
             writer.increaseIndent();
             int stateSize = reusedMap.size();
@@ -158,8 +169,8 @@
         }
 
         ArraySet<String> allWebDomains = mCollector.collectAllWebDomains(pkg);
-        SparseArray<DomainVerificationUserState> userStates =
-                pkgState.getUserSelectionStates();
+        SparseArray<DomainVerificationInternalUserState> userStates =
+                pkgState.getUserStates();
         if (userId == UserHandle.USER_ALL) {
             int size = userStates.size();
             if (size == 0) {
@@ -167,13 +178,13 @@
                         wasHeaderPrinted);
             } else {
                 for (int index = 0; index < size; index++) {
-                    DomainVerificationUserState userState = userStates.valueAt(index);
+                    DomainVerificationInternalUserState userState = userStates.valueAt(index);
                     printState(writer, pkgState, userState.getUserId(), userState, reusedSet,
                             allWebDomains, wasHeaderPrinted);
                 }
             }
         } else {
-            DomainVerificationUserState userState = userStates.get(userId);
+            DomainVerificationInternalUserState userState = userStates.get(userId);
             printState(writer, pkgState, userId, userState, reusedSet, allWebDomains,
                     wasHeaderPrinted);
         }
@@ -181,8 +192,9 @@
 
     boolean printState(@NonNull IndentingPrintWriter writer,
             @NonNull DomainVerificationPkgState pkgState, @UserIdInt int userId,
-            @Nullable DomainVerificationUserState userState, @NonNull ArraySet<String> reusedSet,
-            @NonNull ArraySet<String> allWebDomains, boolean wasHeaderPrinted) {
+            @Nullable DomainVerificationInternalUserState userState,
+            @NonNull ArraySet<String> reusedSet, @NonNull ArraySet<String> allWebDomains,
+            boolean wasHeaderPrinted) {
         reusedSet.clear();
         reusedSet.addAll(allWebDomains);
         if (userState != null) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
index ed37fa0..1721a18 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
@@ -132,6 +132,21 @@
     /**
      * Enforced when mutating user selection state inside an exposed API method.
      */
+    public boolean assertApprovedUserStateQuerent(int callingUid, @UserIdInt int callingUserId,
+            @NonNull String packageName, @UserIdInt int targetUserId) throws SecurityException {
+        if (callingUserId != targetUserId) {
+            mContext.enforcePermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    Binder.getCallingPid(), callingUid,
+                    "Caller is not allowed to edit other users");
+        }
+
+        return !mCallback.filterAppAccess(packageName, callingUid, targetUserId);
+    }
+
+    /**
+     * Enforced when mutating user selection state inside an exposed API method.
+     */
     public boolean assertApprovedUserSelector(int callingUid, @UserIdInt int callingUserId,
             @Nullable String packageName, @UserIdInt int targetUserId) throws SecurityException {
         if (callingUserId != targetUserId) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
index c787356..4bad102 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
@@ -32,7 +32,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
-import java.util.Map;
 
 /**
  * Reads and writes the old {@link android.content.pm.IntentFilterVerificationInfo} so that it can
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 9e22d82..0c2b4c5 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -48,7 +48,7 @@
 import java.util.UUID;
 import java.util.function.Function;
 
-public interface DomainVerificationManagerInternal extends DomainVerificationManager {
+public interface DomainVerificationManagerInternal {
 
     UUID DISABLED_ID = new UUID(0, 0);
 
@@ -69,8 +69,8 @@
      * during the legacy transition period.
      *
      * TODO(b/177923646): The legacy values can be removed once the Settings API changes are
-     *  shipped. These values are not stable, so just deleting the constant and shifting others is
-     *  fine.
+     * shipped. These values are not stable, so just deleting the constant and shifting others is
+     * fine.
      */
     int APPROVAL_LEVEL_LEGACY_ASK = 1;
 
@@ -84,14 +84,15 @@
 
     /**
      * The app has been chosen by the user through
-     * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)}, indictag an explicit
-     * choice to use this app to open an unverified domain.
+     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
+     * indicating an explicit choice to use this app to open an unverified domain.
      */
     int APPROVAL_LEVEL_SELECTION = 2;
 
     /**
      * The app is approved through the digital asset link statement being hosted at the domain
-     * it is capturing. This is set through {@link #setDomainVerificationStatus(UUID, Set, int)} by
+     * it is capturing. This is set through
+     * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by
      * the domain verification agent on device.
      */
     int APPROVAL_LEVEL_VERIFIED = 3;
@@ -102,7 +103,7 @@
      * declares against the digital asset link statements before allowing it to be installed.
      *
      * The user is still able to disable instant app link handling through
-     * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
+     * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}.
      */
     int APPROVAL_LEVEL_INSTANT_APP = 4;
 
@@ -122,7 +123,17 @@
             APPROVAL_LEVEL_VERIFIED,
             APPROVAL_LEVEL_INSTANT_APP
     })
-    @interface ApprovalLevel{}
+    @interface ApprovalLevel {
+    }
+
+    /** @see DomainVerificationManager#getDomainVerificationInfo(String) */
+    @Nullable
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
+            android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
+    })
+    DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
+            throws NameNotFoundException;
 
     /**
      * Generate a new domain set ID to be used for attaching new packages.
@@ -173,9 +184,9 @@
     /**
      * Migrates verification state from a previous install to a new one. It is expected that the
      * {@link PackageSetting#getDomainSetId()} already be set to the correct value, usually from
-     * {@link #generateNewId()}. This will preserve {@link #STATE_SUCCESS} domains under the
-     * assumption that the new package will pass the same server side config as the previous
-     * package, as they have matching signatures.
+     * {@link #generateNewId()}. This will preserve {@link DomainVerificationManager#STATE_SUCCESS}
+     * domains under the assumption that the new package will pass the same server side config as
+     * the previous package, as they have matching signatures.
      * <p>
      * This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal
      * lock. This should never be called from within the domain verification classes themselves.
@@ -229,8 +240,10 @@
      * tag has already been entered.
      * <p>
      * This is <b>only</b> for restore, and will override package states, ignoring if their {@link
-     * DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains marked
-     * as success verify against the server correctly, although the verification agent may decide to
+     * DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains
+     * marked
+     * as success verify against the server correctly, although the verification agent may decide
+     * to
      * re-verify them when it gets the chance.
      */
     /*
@@ -310,6 +323,7 @@
      */
     @ApprovalLevel
     int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
+            @NonNull List<ResolveInfo> candidates,
             @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId);
 
     /**
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
index 6f28107..a7a52e0 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
@@ -23,29 +23,29 @@
 import android.content.pm.verify.domain.DomainOwner;
 import android.content.pm.verify.domain.DomainSet;
 import android.content.pm.verify.domain.DomainVerificationInfo;
+import android.content.pm.verify.domain.DomainVerificationManager;
 import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
-import android.content.pm.verify.domain.DomainVerificationManagerImpl;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
 import android.content.pm.verify.domain.IDomainVerificationManager;
 import android.os.ServiceSpecificException;
 
 import java.util.List;
 import java.util.UUID;
 
-class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
+public class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
 
     @NonNull
-    private DomainVerificationService mService;
+    private final DomainVerificationService mService;
 
-    DomainVerificationManagerStub(DomainVerificationService service) {
+    public DomainVerificationManagerStub(DomainVerificationService service) {
         mService = service;
     }
 
     @NonNull
     @Override
-    public List<String> getValidVerificationPackageNames() {
+    public List<String> queryValidVerificationPackageNames() {
         try {
-            return mService.getValidVerificationPackageNames();
+            return mService.queryValidVerificationPackageNames();
         } catch (Exception e) {
             throw rethrow(e);
         }
@@ -95,10 +95,10 @@
 
     @Nullable
     @Override
-    public DomainVerificationUserSelection getDomainVerificationUserSelection(
+    public DomainVerificationUserState getDomainVerificationUserState(
             String packageName, @UserIdInt int userId) {
         try {
-            return mService.getDomainVerificationUserSelection(packageName, userId);
+            return mService.getDomainVerificationUserState(packageName, userId);
         } catch (Exception e) {
             throw rethrow(e);
         }
@@ -117,13 +117,13 @@
 
     private RuntimeException rethrow(Exception exception) throws RuntimeException {
         if (exception instanceof InvalidDomainSetException) {
-            int packedErrorCode = DomainVerificationManagerImpl.ERROR_INVALID_DOMAIN_SET;
+            int packedErrorCode = DomainVerificationManager.ERROR_INVALID_DOMAIN_SET;
             packedErrorCode |= ((InvalidDomainSetException) exception).getReason() << 16;
             return new ServiceSpecificException(packedErrorCode,
                     ((InvalidDomainSetException) exception).getPackageName());
         } else if (exception instanceof NameNotFoundException) {
             return new ServiceSpecificException(
-                    DomainVerificationManagerImpl.ERROR_NAME_NOT_FOUND);
+                    DomainVerificationManager.ERROR_NAME_NOT_FOUND);
         } else if (exception instanceof RuntimeException) {
             return (RuntimeException) exception;
         } else {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
index c864b29..abb8d2f 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
@@ -27,9 +27,9 @@
 import android.util.TypedXmlSerializer;
 
 import com.android.server.pm.SettingsXml;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
 import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -157,7 +157,7 @@
         UUID id = UUID.fromString(idString);
 
         final ArrayMap<String, Integer> stateMap = new ArrayMap<>();
-        final SparseArray<DomainVerificationUserState> userStates = new SparseArray<>();
+        final SparseArray<DomainVerificationInternalUserState> userStates = new SparseArray<>();
 
         SettingsXml.ChildSection child = section.children();
         while (child.moveToNext()) {
@@ -176,10 +176,10 @@
     }
 
     private static void readUserStates(@NonNull SettingsXml.ReadSection section,
-            @NonNull SparseArray<DomainVerificationUserState> userStates) {
+            @NonNull SparseArray<DomainVerificationInternalUserState> userStates) {
         SettingsXml.ChildSection child = section.children();
         while (child.moveToNext(TAG_USER_STATE)) {
-            DomainVerificationUserState userState = createUserStateFromXml(child);
+            DomainVerificationInternalUserState userState = createUserStateFromXml(child);
             if (userState != null) {
                 userStates.put(userState.getUserId(), userState);
             }
@@ -205,12 +205,12 @@
                              .attribute(ATTR_HAS_AUTO_VERIFY_DOMAINS,
                                      pkgState.isHasAutoVerifyDomains())) {
             writeStateMap(parentSection, pkgState.getStateMap());
-            writeUserStates(parentSection, pkgState.getUserSelectionStates());
+            writeUserStates(parentSection, pkgState.getUserStates());
         }
     }
 
     private static void writeUserStates(@NonNull SettingsXml.WriteSection parentSection,
-            @NonNull SparseArray<DomainVerificationUserState> states) throws IOException {
+            @NonNull SparseArray<DomainVerificationInternalUserState> states) throws IOException {
         int size = states.size();
         if (size == 0) {
             return;
@@ -245,7 +245,7 @@
      * entered.
      */
     @Nullable
-    public static DomainVerificationUserState createUserStateFromXml(
+    public static DomainVerificationInternalUserState createUserStateFromXml(
             @NonNull SettingsXml.ReadSection section) {
         int userId = section.getInt(ATTR_USER_ID);
         if (userId == -1) {
@@ -260,7 +260,7 @@
             readEnabledHosts(child, enabledHosts);
         }
 
-        return new DomainVerificationUserState(userId, enabledHosts, allowLinkHandling);
+        return new DomainVerificationInternalUserState(userId, enabledHosts, allowLinkHandling);
     }
 
     private static void readEnabledHosts(@NonNull SettingsXml.ReadSection section,
@@ -275,7 +275,7 @@
     }
 
     public static void writeUserStateToXml(@NonNull SettingsXml.WriteSection parentSection,
-            @NonNull DomainVerificationUserState userState) throws IOException {
+            @NonNull DomainVerificationInternalUserState userState) throws IOException {
         try (SettingsXml.WriteSection section =
                      parentSection.startSection(TAG_USER_STATE)
                              .attribute(ATTR_USER_ID, userState.getUserId())
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index b58c1ff..e85bbe4 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -34,8 +34,9 @@
 import android.content.pm.verify.domain.DomainOwner;
 import android.content.pm.verify.domain.DomainVerificationInfo;
 import android.content.pm.verify.domain.DomainVerificationManager;
+import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
 import android.content.pm.verify.domain.DomainVerificationState;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
 import android.content.pm.verify.domain.IDomainVerificationManager;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -55,9 +56,9 @@
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
 import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyUnavailable;
 
@@ -208,8 +209,7 @@
     }
 
     @NonNull
-    @Override
-    public List<String> getValidVerificationPackageNames() {
+    public List<String> queryValidVerificationPackageNames() {
         mEnforcer.assertApprovedVerifier(mConnection.getCallingUid(), mProxy);
         List<String> packageNames = new ArrayList<>();
         synchronized (mLock) {
@@ -256,7 +256,7 @@
             Map<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap());
 
             // TODO(b/159952358): Should the domain list be cached?
-            ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+            ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
             if (domains.isEmpty()) {
                 return null;
             }
@@ -272,7 +272,6 @@
         }
     }
 
-    @Override
     public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
             int state) throws InvalidDomainSetException, NameNotFoundException {
         if (state < DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED) {
@@ -314,7 +313,7 @@
 
             int size = verifiedDomains.size();
             for (int index = 0; index < size; index++) {
-                removeUserSelectionsForDomain(verifiedDomains.get(index));
+                removeUserStatesForDomain(verifiedDomains.get(index));
             }
         }
 
@@ -354,7 +353,8 @@
 
                     validDomains.clear();
 
-                    ArraySet<String> autoVerifyDomains = mCollector.collectAutoVerifyDomains(pkg);
+                    ArraySet<String> autoVerifyDomains =
+                            mCollector.collectValidAutoVerifyDomains(pkg);
                     if (domains == null) {
                         validDomains.addAll(autoVerifyDomains);
                     } else {
@@ -379,9 +379,9 @@
 
                 AndroidPackage pkg = pkgSetting.getPkg();
                 if (domains == null) {
-                    domains = mCollector.collectAutoVerifyDomains(pkg);
+                    domains = mCollector.collectValidAutoVerifyDomains(pkg);
                 } else {
-                    domains.retainAll(mCollector.collectAutoVerifyDomains(pkg));
+                    domains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg));
                 }
 
                 setDomainVerificationStatusInternal(pkgState, state, domains);
@@ -400,12 +400,12 @@
         }
     }
 
-    private void removeUserSelectionsForDomain(@NonNull String domain) {
+    private void removeUserStatesForDomain(@NonNull String domain) {
         synchronized (mLock) {
             final int size = mAttachedPkgStates.size();
             for (int index = 0; index < size; index++) {
                 DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
-                SparseArray<DomainVerificationUserState> array = pkgState.getUserSelectionStates();
+                SparseArray<DomainVerificationInternalUserState> array = pkgState.getUserStates();
                 int arraySize = array.size();
                 for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) {
                     array.valueAt(arrayIndex).removeHost(domain);
@@ -414,13 +414,6 @@
         }
     }
 
-    @Override
-    public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
-            boolean allowed) throws NameNotFoundException {
-        setDomainVerificationLinkHandlingAllowed(packageName, allowed,
-                mConnection.getCallingUserId());
-    }
-
     public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
             boolean allowed, @UserIdInt int userId) throws NameNotFoundException {
         if (!mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
@@ -433,7 +426,7 @@
                 throw DomainVerificationUtils.throwPackageUnavailable(packageName);
             }
 
-            pkgState.getOrCreateUserSelectionState(userId)
+            pkgState.getOrCreateUserState(userId)
                     .setLinkHandlingAllowed(allowed);
         }
 
@@ -451,11 +444,11 @@
                     DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(pkgStateIndex);
                     if (userId == UserHandle.USER_ALL) {
                         for (int aUserId : mConnection.getAllUserIds()) {
-                            pkgState.getOrCreateUserSelectionState(aUserId)
+                            pkgState.getOrCreateUserState(aUserId)
                                     .setLinkHandlingAllowed(allowed);
                         }
                     } else {
-                        pkgState.getOrCreateUserSelectionState(userId)
+                        pkgState.getOrCreateUserState(userId)
                                 .setLinkHandlingAllowed(allowed);
                     }
                 }
@@ -467,7 +460,7 @@
                     throw DomainVerificationUtils.throwPackageUnavailable(packageName);
                 }
 
-                pkgState.getOrCreateUserSelectionState(userId)
+                pkgState.getOrCreateUserState(userId)
                         .setLinkHandlingAllowed(allowed);
             }
         }
@@ -475,14 +468,6 @@
         mConnection.scheduleWriteSettings();
     }
 
-    @Override
-    public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
-            @NonNull Set<String> domains, boolean enabled)
-            throws InvalidDomainSetException, NameNotFoundException {
-        setDomainVerificationUserSelection(domainSetId, domains, enabled,
-                mConnection.getCallingUserId());
-    }
-
     public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
             @NonNull Set<String> domains, boolean enabled, @UserIdInt int userId)
             throws InvalidDomainSetException, NameNotFoundException {
@@ -499,7 +484,8 @@
 
             DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
                     false /* forAutoVerify */, callingUid, userId);
-            DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
+            DomainVerificationInternalUserState userState =
+                    pkgState.getOrCreateUserState(userId);
 
             // Disable other packages if approving this one. Note that this check is only done for
             // enabling. This allows an escape hatch in case multiple packages somehow get selected.
@@ -539,8 +525,8 @@
                             continue;
                         }
 
-                        DomainVerificationUserState approvedUserState =
-                                approvedPkgState.getUserSelectionState(userId);
+                        DomainVerificationInternalUserState approvedUserState =
+                                approvedPkgState.getUserState(userId);
                         if (approvedUserState == null) {
                             continue;
                         }
@@ -622,8 +608,8 @@
 
         if (userId == UserHandle.USER_ALL) {
             for (int aUserId : mConnection.getAllUserIds()) {
-                DomainVerificationUserState userState =
-                        pkgState.getOrCreateUserSelectionState(aUserId);
+                DomainVerificationInternalUserState userState =
+                        pkgState.getOrCreateUserState(aUserId);
                 if (enabled) {
                     userState.addHosts(domains);
                 } else {
@@ -631,7 +617,8 @@
                 }
             }
         } else {
-            DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
+            DomainVerificationInternalUserState userState =
+                    pkgState.getOrCreateUserState(userId);
             if (enabled) {
                 userState.addHosts(domains);
             } else {
@@ -642,17 +629,9 @@
 
     @Nullable
     @Override
-    public DomainVerificationUserSelection getDomainVerificationUserSelection(
-            @NonNull String packageName) throws NameNotFoundException {
-        return getDomainVerificationUserSelection(packageName,
-                mConnection.getCallingUserId());
-    }
-
-    @Nullable
-    @Override
-    public DomainVerificationUserSelection getDomainVerificationUserSelection(
+    public DomainVerificationUserState getDomainVerificationUserState(
             @NonNull String packageName, @UserIdInt int userId) throws NameNotFoundException {
-        if (!mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
+        if (!mEnforcer.assertApprovedUserStateQuerent(mConnection.getCallingUid(),
                 mConnection.getCallingUserId(), packageName, userId)) {
             throw DomainVerificationUtils.throwPackageUnavailable(packageName);
         }
@@ -672,7 +651,7 @@
 
             Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
             ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
-            DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
+            DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
             Set<String> enabledHosts = userState == null ? emptySet() : userState.getEnabledHosts();
 
             for (int index = 0; index < webDomainsSize; index++) {
@@ -681,11 +660,11 @@
 
                 int domainState;
                 if (state != null && DomainVerificationManager.isStateVerified(state)) {
-                    domainState = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED;
+                    domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED;
                 } else if (enabledHosts.contains(host)) {
-                    domainState = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED;
+                    domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED;
                 } else {
-                    domainState = DomainVerificationUserSelection.DOMAIN_STATE_NONE;
+                    domainState = DomainVerificationUserState.DOMAIN_STATE_NONE;
                 }
 
                 domains.put(host, domainState);
@@ -693,17 +672,11 @@
 
             boolean linkHandlingAllowed = userState == null || userState.isLinkHandlingAllowed();
 
-            return new DomainVerificationUserSelection(pkgState.getId(), packageName,
+            return new DomainVerificationUserState(pkgState.getId(), packageName,
                     UserHandle.of(userId), linkHandlingAllowed, domains);
         }
     }
 
-    @NonNull
-    @Override
-    public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
-        return getOwnersForDomain(domain, mConnection.getCallingUserId());
-    }
-
     public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
         mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
                 userId);
@@ -794,7 +767,7 @@
             AndroidPackage newPkg = newPkgSetting.getPkg();
 
             ArrayMap<String, Integer> newStateMap = new ArrayMap<>();
-            SparseArray<DomainVerificationUserState> newUserStates = new SparseArray<>();
+            SparseArray<DomainVerificationInternalUserState> newUserStates = new SparseArray<>();
 
             if (oldPkgState == null || oldPkg == null || newPkg == null) {
                 // Should be impossible, but to be safe, continue with a new blank state instead
@@ -811,7 +784,8 @@
             }
 
             ArrayMap<String, Integer> oldStateMap = oldPkgState.getStateMap();
-            ArraySet<String> newAutoVerifyDomains = mCollector.collectAutoVerifyDomains(newPkg);
+            ArraySet<String> newAutoVerifyDomains =
+                    mCollector.collectValidAutoVerifyDomains(newPkg);
             int newDomainsSize = newAutoVerifyDomains.size();
 
             for (int newDomainsIndex = 0; newDomainsIndex < newDomainsSize; newDomainsIndex++) {
@@ -836,21 +810,22 @@
                 }
             }
 
-            SparseArray<DomainVerificationUserState> oldUserStates =
-                    oldPkgState.getUserSelectionStates();
+            SparseArray<DomainVerificationInternalUserState> oldUserStates =
+                    oldPkgState.getUserStates();
             int oldUserStatesSize = oldUserStates.size();
             if (oldUserStatesSize > 0) {
-                ArraySet<String> newWebDomains = mCollector.collectAutoVerifyDomains(newPkg);
+                ArraySet<String> newWebDomains = mCollector.collectValidAutoVerifyDomains(newPkg);
                 for (int oldUserStatesIndex = 0; oldUserStatesIndex < oldUserStatesSize;
                         oldUserStatesIndex++) {
                     int userId = oldUserStates.keyAt(oldUserStatesIndex);
-                    DomainVerificationUserState oldUserState = oldUserStates.valueAt(
+                    DomainVerificationInternalUserState oldUserState = oldUserStates.valueAt(
                             oldUserStatesIndex);
                     ArraySet<String> oldEnabledHosts = oldUserState.getEnabledHosts();
                     ArraySet<String> newEnabledHosts = new ArraySet<>(oldEnabledHosts);
                     newEnabledHosts.retainAll(newWebDomains);
-                    DomainVerificationUserState newUserState = new DomainVerificationUserState(
-                            userId, newEnabledHosts, oldUserState.isLinkHandlingAllowed());
+                    DomainVerificationInternalUserState newUserState =
+                            new DomainVerificationInternalUserState(userId, newEnabledHosts,
+                                    oldUserState.isLinkHandlingAllowed());
                     newUserStates.put(userId, newUserState);
                 }
             }
@@ -893,7 +868,7 @@
         }
 
         AndroidPackage pkg = newPkgSetting.getPkg();
-        ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+        ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
         boolean hasAutoVerifyDomains = !domains.isEmpty();
         boolean isPendingOrRestored = pkgState != null;
         if (isPendingOrRestored) {
@@ -924,7 +899,7 @@
                         webDomains = mCollector.collectAllWebDomains(pkg);
                     }
 
-                    pkgState.getOrCreateUserSelectionState(userId).addHosts(webDomains);
+                    pkgState.getOrCreateUserState(userId).addHosts(webDomains);
                 }
             }
 
@@ -1157,7 +1132,7 @@
         }
         AndroidPackage pkg = pkgSetting.getPkg();
         ArraySet<String> declaredDomains = forAutoVerify
-                ? mCollector.collectAutoVerifyDomains(pkg)
+                ? mCollector.collectValidAutoVerifyDomains(pkg)
                 : mCollector.collectAllWebDomains(pkg);
 
         if (domains.retainAll(declaredDomains)) {
@@ -1289,11 +1264,11 @@
             }
         }
 
-        applyImmutableState(pkgState, mCollector.collectAutoVerifyDomains(pkg));
+        applyImmutableState(pkgState, mCollector.collectValidAutoVerifyDomains(pkg));
     }
 
     @Override
-    public void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId) {
+    public void clearUserStates(@Nullable List<String> packageNames, @UserIdInt int userId) {
         mEnforcer.assertInternal(mConnection.getCallingUid());
         synchronized (mLock) {
             if (packageNames == null) {
@@ -1494,9 +1469,11 @@
 
     @Override
     public int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
+            @NonNull List<ResolveInfo> candidates,
             @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
         String packageName = pkgSetting.getName();
-        if (!DomainVerificationUtils.isDomainVerificationIntent(intent, resolveInfoFlags)) {
+        if (!DomainVerificationUtils.isDomainVerificationIntent(intent, candidates,
+                resolveInfoFlags)) {
             if (DEBUG_APPROVAL) {
                 debugApproval(packageName, intent, userId, false, "not valid intent");
             }
@@ -1541,7 +1518,7 @@
                 return APPROVAL_LEVEL_NONE;
             }
 
-            DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
+            DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
 
             if (userState != null && !userState.isLinkHandlingAllowed()) {
                 if (DEBUG_APPROVAL) {
@@ -1557,7 +1534,7 @@
                 // To allow an instant app to immediately open domains after being installed by the
                 // user, auto approve them for any declared autoVerify domains.
                 if (pkgSetting.getInstantApp(userId)
-                        && mCollector.collectAutoVerifyDomains(pkg).contains(host)) {
+                        && mCollector.collectValidAutoVerifyDomains(pkg).contains(host)) {
                     return APPROVAL_LEVEL_INSTANT_APP;
                 }
             }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
index a8e937c..f3d1dbb 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
@@ -29,9 +29,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
 import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -216,21 +216,22 @@
             }
         }
 
-        SparseArray<DomainVerificationUserState> oldSelectionStates =
-                oldState.getUserSelectionStates();
+        SparseArray<DomainVerificationInternalUserState> oldSelectionStates =
+                oldState.getUserStates();
 
-        SparseArray<DomainVerificationUserState> newSelectionStates =
-                newState.getUserSelectionStates();
+        SparseArray<DomainVerificationInternalUserState> newSelectionStates =
+                newState.getUserStates();
 
-        DomainVerificationUserState newUserState = newSelectionStates.get(UserHandle.USER_SYSTEM);
+        DomainVerificationInternalUserState newUserState =
+                newSelectionStates.get(UserHandle.USER_SYSTEM);
         if (newUserState != null) {
             ArraySet<String> newEnabledHosts = newUserState.getEnabledHosts();
-            DomainVerificationUserState oldUserState =
+            DomainVerificationInternalUserState oldUserState =
                     oldSelectionStates.get(UserHandle.USER_SYSTEM);
 
             boolean linkHandlingAllowed = newUserState.isLinkHandlingAllowed();
             if (oldUserState == null) {
-                oldUserState = new DomainVerificationUserState(UserHandle.USER_SYSTEM,
+                oldUserState = new DomainVerificationInternalUserState(UserHandle.USER_SYSTEM,
                         newEnabledHosts, linkHandlingAllowed);
                 oldSelectionStates.put(UserHandle.USER_SYSTEM, oldUserState);
             } else {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
index d083d11..94767f5 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
@@ -24,7 +24,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.verify.domain.DomainVerificationManager;
 import android.content.pm.verify.domain.DomainVerificationState;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
 import android.os.Binder;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -118,7 +118,7 @@
             case "set-app-links":
                 return runSetAppLinks(commandHandler);
             case "set-app-links-user-selection":
-                return runSetAppLinksUserSelection(commandHandler);
+                return runSetAppLinksUserState(commandHandler);
             case "set-app-links-allowed":
                 return runSetAppLinksAllowed(commandHandler);
         }
@@ -193,7 +193,7 @@
     }
 
     // pm set-app-links-user-selection --user <USER_ID> [--package <PACKAGE>] <ENABLED> <DOMAINS>...
-    private boolean runSetAppLinksUserSelection(@NonNull BasicShellCommandHandler commandHandler) {
+    private boolean runSetAppLinksUserState(@NonNull BasicShellCommandHandler commandHandler) {
         Integer userId = null;
         String packageName = null;
 
@@ -224,7 +224,7 @@
             return false;
         }
 
-        userId = translateUserId(userId, "runSetAppLinksUserSelection");
+        userId = translateUserId(userId, "runSetAppLinksUserState");
 
         String enabledString = commandHandler.getNextArgRequired();
 
@@ -326,7 +326,7 @@
         }
 
         if (userId != null) {
-            mCallback.clearUserSelections(packageNames, userId);
+            mCallback.clearUserStates(packageNames, userId);
         } else {
             mCallback.clearDomainVerificationState(packageNames);
         }
@@ -457,10 +457,10 @@
                 throws PackageManager.NameNotFoundException;
 
         /**
-         * @see DomainVerificationManager#getDomainVerificationUserSelection(String)
+         * @see DomainVerificationManager#getDomainVerificationUserState(String)
          */
         @Nullable
-        DomainVerificationUserSelection getDomainVerificationUserSelection(
+        DomainVerificationUserState getDomainVerificationUserState(
                 @NonNull String packageName, @UserIdInt int userId)
                 throws PackageManager.NameNotFoundException;
 
@@ -486,7 +486,7 @@
          * Reset all the user selections for the given package names, or all package names if null
          * is provided.
          */
-        void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId);
+        void clearUserStates(@Nullable List<String> packageNames, @UserIdInt int userId);
 
         /**
          * Broadcast a verification request for the given package names, or all package names if
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 783aff6..883bbad 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -22,12 +22,17 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.os.Binder;
 
+import com.android.internal.util.CollectionUtils;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
+import java.util.List;
+import java.util.Set;
+
 public final class DomainVerificationUtils {
 
     /**
@@ -40,13 +45,61 @@
         throw new NameNotFoundException("Package " + packageName + " unavailable");
     }
 
-    public static boolean isDomainVerificationIntent(Intent intent, int resolveInfoFlags) {
-        if (!intent.isWebIntent() || !intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
+    public static boolean isDomainVerificationIntent(Intent intent,
+            @NonNull List<ResolveInfo> candidates,
+            @PackageManager.ResolveInfoFlags int resolveInfoFlags) {
+        if (!intent.isWebIntent()) {
             return false;
         }
 
-        return ((resolveInfoFlags & PackageManager.MATCH_DEFAULT_ONLY) != 0)
-                || intent.hasCategory(Intent.CATEGORY_DEFAULT);
+        Set<String> categories = intent.getCategories();
+        int categoriesSize = CollectionUtils.size(categories);
+        if (categoriesSize > 2) {
+            // Specifying at least one non-app-link category
+            return false;
+        } else if (categoriesSize == 2) {
+            // Check for explicit app link intent with exactly BROWSABLE && DEFAULT
+            return intent.hasCategory(Intent.CATEGORY_DEFAULT)
+                    && intent.hasCategory(Intent.CATEGORY_BROWSABLE);
+        }
+
+            // In cases where at least one browser is resolved and only one non-browser is resolved,
+        // the Intent is coerced into an app links intent, under the assumption the browser can
+        // be skipped if the app is approved at any level for the domain.
+        boolean foundBrowser = false;
+        boolean foundOneApp = false;
+
+        final int candidatesSize = candidates.size();
+        for (int index = 0; index < candidatesSize; index++) {
+            final ResolveInfo info = candidates.get(index);
+            if (info.handleAllWebDataURI) {
+                foundBrowser = true;
+            } else if (foundOneApp) {
+                // Already true, so duplicate app
+                foundOneApp = false;
+                break;
+            } else {
+                foundOneApp = true;
+            }
+        }
+
+        boolean matchDefaultByFlags = (resolveInfoFlags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
+        boolean onlyOneNonBrowser = foundBrowser && foundOneApp;
+
+        // Check if matches (BROWSABLE || none) && DEFAULT
+        if (categoriesSize == 0) {
+            // No categories, run coerce case, matching DEFAULT by flags
+            return onlyOneNonBrowser && matchDefaultByFlags;
+        } else if (intent.hasCategory(Intent.CATEGORY_DEFAULT)) {
+            // Run coerce case, matching by explicit DEFAULT
+            return onlyOneNonBrowser;
+        } else if (intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
+            // Intent matches BROWSABLE, must match DEFAULT by flags
+            return matchDefaultByFlags;
+        } else {
+            // Otherwise not matching any app link categories
+            return false;
+        }
     }
 
     static boolean isChangeEnabled(PlatformCompat platformCompat, AndroidPackage pkg,
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
similarity index 74%
rename from services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
rename to services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
index 8fbb33a..aa7407c 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
@@ -29,7 +29,7 @@
  * when a web URL Intent is sent and the application is the highest priority for that domain.
  */
 @DataClass(genSetters = true, genEqualsHashCode = true, genToString = true, genBuilder = false)
-public class DomainVerificationUserState {
+public class DomainVerificationInternalUserState {
 
     @UserIdInt
     private final int mUserId;
@@ -43,32 +43,32 @@
      */
     private boolean mLinkHandlingAllowed = true;
 
-    public DomainVerificationUserState(@UserIdInt int userId) {
+    public DomainVerificationInternalUserState(@UserIdInt int userId) {
         mUserId = userId;
         mEnabledHosts = new ArraySet<>();
     }
 
-    public DomainVerificationUserState addHosts(@NonNull ArraySet<String> newHosts) {
+    public DomainVerificationInternalUserState addHosts(@NonNull ArraySet<String> newHosts) {
         mEnabledHosts.addAll(newHosts);
         return this;
     }
 
-    public DomainVerificationUserState addHosts(@NonNull Set<String> newHosts) {
+    public DomainVerificationInternalUserState addHosts(@NonNull Set<String> newHosts) {
         mEnabledHosts.addAll(newHosts);
         return this;
     }
 
-    public DomainVerificationUserState removeHost(String host) {
+    public DomainVerificationInternalUserState removeHost(String host) {
         mEnabledHosts.remove(host);
         return this;
     }
 
-    public DomainVerificationUserState removeHosts(@NonNull ArraySet<String> newHosts) {
+    public DomainVerificationInternalUserState removeHosts(@NonNull ArraySet<String> newHosts) {
         mEnabledHosts.removeAll(newHosts);
         return this;
     }
 
-    public DomainVerificationUserState removeHosts(@NonNull Set<String> newHosts) {
+    public DomainVerificationInternalUserState removeHosts(@NonNull Set<String> newHosts) {
         mEnabledHosts.removeAll(newHosts);
         return this;
     }
@@ -81,8 +81,7 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm
-    // /verify/domain/models/DomainVerificationUserState.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -90,7 +89,7 @@
 
 
     /**
-     * Creates a new DomainVerificationUserState.
+     * Creates a new DomainVerificationInternalUserState.
      *
      * @param enabledHosts
      *   List of domains which have been enabled by the user. *
@@ -98,7 +97,7 @@
      *   Whether to allow this package to automatically open links by auto verification.
      */
     @DataClass.Generated.Member
-    public DomainVerificationUserState(
+    public DomainVerificationInternalUserState(
             @UserIdInt int userId,
             @NonNull ArraySet<String> enabledHosts,
             boolean linkHandlingAllowed) {
@@ -138,7 +137,7 @@
      * Whether to allow this package to automatically open links by auto verification.
      */
     @DataClass.Generated.Member
-    public @NonNull DomainVerificationUserState setLinkHandlingAllowed( boolean value) {
+    public @NonNull DomainVerificationInternalUserState setLinkHandlingAllowed( boolean value) {
         mLinkHandlingAllowed = value;
         return this;
     }
@@ -149,7 +148,7 @@
         // You can override field toString logic by defining methods like:
         // String fieldNameToString() { ... }
 
-        return "DomainVerificationUserState { " +
+        return "DomainVerificationInternalUserState { " +
                 "userId = " + mUserId + ", " +
                 "enabledHosts = " + mEnabledHosts + ", " +
                 "linkHandlingAllowed = " + mLinkHandlingAllowed +
@@ -160,13 +159,13 @@
     @DataClass.Generated.Member
     public boolean equals(@android.annotation.Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
-        // boolean fieldNameEquals(DomainVerificationUserState other) { ... }
+        // boolean fieldNameEquals(DomainVerificationInternalUserState other) { ... }
         // boolean fieldNameEquals(FieldType otherValue) { ... }
 
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         @SuppressWarnings("unchecked")
-        DomainVerificationUserState that = (DomainVerificationUserState) o;
+        DomainVerificationInternalUserState that = (DomainVerificationInternalUserState) o;
         //noinspection PointlessBooleanExpression
         return true
                 && mUserId == that.mUserId
@@ -188,10 +187,10 @@
     }
 
     @DataClass.Generated(
-            time = 1612894390039L,
+            time = 1614714563905L,
             codegenVersion = "1.0.22",
-            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java",
-            inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledHosts\nprivate  boolean mLinkHandlingAllowed\npublic  com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationUserState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genEqualsHashCode=true, genToString=true, genBuilder=false)")
+            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java",
+            inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledHosts\nprivate  boolean mLinkHandlingAllowed\npublic  com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState addHosts(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHost(java.lang.String)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationInternalUserState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genEqualsHashCode=true, genToString=true, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
index 48099aa..a089a60 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.content.pm.verify.domain.DomainVerificationManager;
 import android.content.pm.verify.domain.DomainVerificationState;
 import android.util.ArrayMap;
 import android.util.SparseArray;
@@ -44,9 +43,9 @@
 
     /**
      * Whether or not the package declares any autoVerify domains. This is separate from an empty
-     * check on the map itself, because an empty map means no response recorded, not necessarily no
-     * domains declared. When this is false, {@link #mStateMap} will be empty, but
-     * {@link #mUserSelectionStates} may contain any domains the user has explicitly chosen to
+     * check on the map itself, because an empty map means no response recorded, not necessarily
+     * no domains declared. When this is false, {@link #mStateMap} will be empty, but
+     * {@link #mUserStates} may contain any domains the user has explicitly chosen to
      * allow this package to open, which may or may not be marked autoVerify.
      */
     private final boolean mHasAutoVerifyDomains;
@@ -62,7 +61,7 @@
     private final ArrayMap<String, Integer> mStateMap;
 
     @NonNull
-    private final SparseArray<DomainVerificationUserState> mUserSelectionStates;
+    private final SparseArray<DomainVerificationInternalUserState> mUserStates;
 
     public DomainVerificationPkgState(@NonNull String packageName, @NonNull UUID id,
             boolean hasAutoVerifyDomains) {
@@ -70,16 +69,17 @@
     }
 
     @Nullable
-    public DomainVerificationUserState getUserSelectionState(@UserIdInt int userId) {
-        return mUserSelectionStates.get(userId);
+    public DomainVerificationInternalUserState getUserState(@UserIdInt int userId) {
+        return mUserStates.get(userId);
     }
 
     @Nullable
-    public DomainVerificationUserState getOrCreateUserSelectionState(@UserIdInt int userId) {
-        DomainVerificationUserState userState = mUserSelectionStates.get(userId);
+    public DomainVerificationInternalUserState getOrCreateUserState(
+            @UserIdInt int userId) {
+        DomainVerificationInternalUserState userState = mUserStates.get(userId);
         if (userState == null) {
-            userState = new DomainVerificationUserState(userId);
-            mUserSelectionStates.put(userId, userState);
+            userState = new DomainVerificationInternalUserState(userId);
+            mUserStates.put(userId, userState);
         }
         return userState;
     }
@@ -89,20 +89,20 @@
     }
 
     public void removeUser(@UserIdInt int userId) {
-        mUserSelectionStates.remove(userId);
+        mUserStates.remove(userId);
     }
 
     public void removeAllUsers() {
-        mUserSelectionStates.clear();
+        mUserStates.clear();
     }
 
-    private int userSelectionStatesHashCode() {
-        return mUserSelectionStates.contentHashCode();
+    private int userStatesHashCode() {
+        return mUserStates.contentHashCode();
     }
 
-    private boolean userSelectionStatesEquals(
-            @NonNull SparseArray<DomainVerificationUserState> other) {
-        return mUserSelectionStates.contentEquals(other);
+    private boolean userStatesEquals(
+            @NonNull SparseArray<DomainVerificationInternalUserState> other) {
+        return mUserStates.contentEquals(other);
     }
 
 
@@ -113,7 +113,7 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationPkgState.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -123,9 +123,15 @@
     /**
      * Creates a new DomainVerificationPkgState.
      *
+     * @param hasAutoVerifyDomains
+     *   Whether or not the package declares any autoVerify domains. This is separate from an empty
+     *   check on the map itself, because an empty map means no response recorded, not necessarily
+     *   no domains declared. When this is false, {@link #mStateMap} will be empty, but
+     *   {@link #mUserStates} may contain any domains the user has explicitly chosen to
+     *   allow this package to open, which may or may not be marked autoVerify.
      * @param stateMap
      *   Map of domains to state integers. Only domains that are not set to the default value of
-     *   {@link DomainVerificationManager#STATE_NO_RESPONSE} are included.
+     *   {@link DomainVerificationState#STATE_NO_RESPONSE} are included.
      *
      *   TODO(b/159952358): Hide the state map entirely from the caller, to allow optimizations,
      *    such as storing no state when the package is marked as a linked app in SystemConfig.
@@ -136,7 +142,7 @@
             @NonNull UUID id,
             boolean hasAutoVerifyDomains,
             @NonNull ArrayMap<String,Integer> stateMap,
-            @NonNull SparseArray<DomainVerificationUserState> userSelectionStates) {
+            @NonNull SparseArray<DomainVerificationInternalUserState> userStates) {
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPackageName);
@@ -147,9 +153,9 @@
         this.mStateMap = stateMap;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mStateMap);
-        this.mUserSelectionStates = userSelectionStates;
+        this.mUserStates = userStates;
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mUserSelectionStates);
+                NonNull.class, null, mUserStates);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -164,6 +170,13 @@
         return mId;
     }
 
+    /**
+     * Whether or not the package declares any autoVerify domains. This is separate from an empty
+     * check on the map itself, because an empty map means no response recorded, not necessarily
+     * no domains declared. When this is false, {@link #mStateMap} will be empty, but
+     * {@link #mUserStates} may contain any domains the user has explicitly chosen to
+     * allow this package to open, which may or may not be marked autoVerify.
+     */
     @DataClass.Generated.Member
     public boolean isHasAutoVerifyDomains() {
         return mHasAutoVerifyDomains;
@@ -171,7 +184,7 @@
 
     /**
      * Map of domains to state integers. Only domains that are not set to the default value of
-     * {@link DomainVerificationManager#STATE_NO_RESPONSE} are included.
+     * {@link DomainVerificationState#STATE_NO_RESPONSE} are included.
      *
      * TODO(b/159952358): Hide the state map entirely from the caller, to allow optimizations,
      *  such as storing no state when the package is marked as a linked app in SystemConfig.
@@ -182,8 +195,8 @@
     }
 
     @DataClass.Generated.Member
-    public @NonNull SparseArray<DomainVerificationUserState> getUserSelectionStates() {
-        return mUserSelectionStates;
+    public @NonNull SparseArray<DomainVerificationInternalUserState> getUserStates() {
+        return mUserStates;
     }
 
     @Override
@@ -197,7 +210,7 @@
                 "id = " + mId + ", " +
                 "hasAutoVerifyDomains = " + mHasAutoVerifyDomains + ", " +
                 "stateMap = " + mStateMap + ", " +
-                "userSelectionStates = " + mUserSelectionStates +
+                "userStates = " + mUserStates +
         " }";
     }
 
@@ -218,7 +231,7 @@
                 && Objects.equals(mId, that.mId)
                 && mHasAutoVerifyDomains == that.mHasAutoVerifyDomains
                 && Objects.equals(mStateMap, that.mStateMap)
-                && userSelectionStatesEquals(that.mUserSelectionStates);
+                && userStatesEquals(that.mUserStates);
     }
 
     @Override
@@ -232,15 +245,15 @@
         _hash = 31 * _hash + Objects.hashCode(mId);
         _hash = 31 * _hash + Boolean.hashCode(mHasAutoVerifyDomains);
         _hash = 31 * _hash + Objects.hashCode(mStateMap);
-        _hash = 31 * _hash + userSelectionStatesHashCode();
+        _hash = 31 * _hash + userStatesHashCode();
         return _hash;
     }
 
     @DataClass.Generated(
-            time = 1608234185474L,
+            time = 1614818362549L,
             codegenVersion = "1.0.22",
-            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationPkgState.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull java.util.UUID mId\nprivate final  boolean mHasAutoVerifyDomains\nprivate final @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.Integer> mStateMap\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationUserState> mUserSelectionStates\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationUserState getUserSelectionState(int)\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationUserState getOrCreateUserSelectionState(int)\npublic  void setId(java.util.UUID)\npublic  void removeUser(int)\npublic  void removeAllUsers()\nprivate  int userSelectionStatesHashCode()\nprivate  boolean userSelectionStatesEquals(android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationUserState>)\nclass DomainVerificationPkgState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
+            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java",
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull java.util.UUID mId\nprivate final  boolean mHasAutoVerifyDomains\nprivate final @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.Integer> mStateMap\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState> mUserStates\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState getUserState(int)\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState getOrCreateUserState(int)\npublic  void setId(java.util.UUID)\npublic  void removeUser(int)\npublic  void removeAllUsers()\nprivate  int userStatesHashCode()\nprivate  boolean userStatesEquals(android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState>)\nclass DomainVerificationPkgState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index a804065..18042af 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm.verify.domain.proxy;
 
+import static android.os.PowerWhitelistManager.REASON_DOMAIN_VERIFICATION_V1;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -238,7 +241,8 @@
         final long allowListTimeout = mConnection.getPowerSaveTempWhitelistAppDuration();
         mConnection.getDeviceIdleInternal().addPowerSaveTempWhitelistApp(Process.myUid(),
                 mVerifierComponent.getPackageName(), allowListTimeout,
-                UserHandle.USER_SYSTEM, true, "domain verification agent");
+                UserHandle.USER_SYSTEM, true, REASON_DOMAIN_VERIFICATION_V1,
+                "domain verification agent");
 
         int size = verifications.size();
         for (int index = 0; index < size; index++) {
@@ -261,7 +265,9 @@
                     .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
 
             final BroadcastOptions options = BroadcastOptions.makeBasic();
-            options.setTemporaryAppWhitelistDuration(allowListTimeout);
+            options.setTemporaryAppAllowlist(allowListTimeout,
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    REASON_DOMAIN_VERIFICATION_V1, "");
             mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null, options.toBundle());
         }
     }
@@ -270,7 +276,7 @@
     private String buildHostsString(@NonNull AndroidPackage pkg) {
         // The collector itself handles the v1 vs v2 behavior, which is based on targetSdkVersion,
         // not the version of the verification agent on device.
-        ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+        ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
 
         // v1 doesn't handle wildcard domains, so transform them here to the root
         StringBuilder builder = new StringBuilder();
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
index 1ef06036..2ba17d3 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm.verify.domain.proxy;
 
+import static android.os.PowerWhitelistManager.REASON_DOMAIN_VERIFICATION_V2;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
@@ -69,11 +72,14 @@
 
                 final long allowListTimeout = mConnection.getPowerSaveTempWhitelistAppDuration();
                 final BroadcastOptions options = BroadcastOptions.makeBasic();
-                options.setTemporaryAppWhitelistDuration(allowListTimeout);
+                options.setTemporaryAppAllowlist(allowListTimeout,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                        REASON_DOMAIN_VERIFICATION_V2, "");
 
                 mConnection.getDeviceIdleInternal().addPowerSaveTempWhitelistApp(Process.myUid(),
                         mVerifierComponent.getPackageName(), allowListTimeout,
-                        UserHandle.USER_SYSTEM, true, "domain verification agent");
+                        UserHandle.USER_SYSTEM, true, REASON_DOMAIN_VERIFICATION_V2,
+                        "domain verification agent");
 
                 Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION)
                         .setComponent(mVerifierComponent)
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index 82fc22c..0e12584 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -74,7 +74,7 @@
         mHandler = handler;
 
         DeviceStateManager deviceStateManager = context.getSystemService(DeviceStateManager.class);
-        deviceStateManager.addDeviceStateListener(new HandlerExecutor(handler),
+        deviceStateManager.registerCallback(new HandlerExecutor(handler),
                 new DeviceStateListener(context));
     }
 
@@ -208,7 +208,7 @@
      * matches the value in the {@link com.android.internal.R.integer.config_foldedDeviceState}
      * resource.
      */
-    private class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+    private class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
         private final int[] mFoldedDeviceStates;
 
         DeviceStateListener(Context context) {
@@ -217,7 +217,7 @@
         }
 
         @Override
-        public void onDeviceStateChanged(int deviceState) {
+        public void onStateChanged(int deviceState) {
             boolean folded = false;
             for (int i = 0; i < mFoldedDeviceStates.length; i++) {
                 if (deviceState == mFoldedDeviceStates[i]) {
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 7f55723..84ac124 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -102,11 +102,9 @@
     }
 
     /**
-     * Check if the key event could be intercepted by combination key rule before it is dispatched
-     * to a window.
-     * Return true if any active rule could be triggered by the key event, otherwise false.
+     * Check if the key event could be triggered by combine key rule before dispatching to a window.
      */
-    boolean interceptKey(KeyEvent event, boolean interactive) {
+    void interceptKey(KeyEvent event, boolean interactive) {
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final int keyCode = event.getKeyCode();
         final int count = mActiveRules.size();
@@ -119,9 +117,9 @@
                     // exceed time from first key down.
                     forAllRules(mActiveRules, (rule)-> rule.cancel());
                     mActiveRules.clear();
-                    return false;
+                    return;
                 } else if (count == 0) { // has some key down but no active rule exist.
-                    return false;
+                    return;
                 }
             }
 
@@ -129,7 +127,7 @@
                 mDownTimes.put(keyCode, eventTime);
             } else {
                 // ignore old key, maybe a repeat key.
-                return false;
+                return;
             }
 
             if (mDownTimes.size() == 1) {
@@ -143,7 +141,7 @@
             } else {
                 // Ignore if rule already triggered.
                 if (mTriggeredRule != null) {
-                    return true;
+                    return;
                 }
 
                 // check if second key can trigger rule, or remove the non-match rule.
@@ -158,7 +156,6 @@
                 mActiveRules.clear();
                 if (mTriggeredRule != null) {
                     mActiveRules.add(mTriggeredRule);
-                    return true;
                 }
             }
         } else {
@@ -171,7 +168,6 @@
                 }
             }
         }
-        return false;
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
new file mode 100644
index 0000000..a0771c0
--- /dev/null
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+
+import com.android.internal.policy.IShortcutService;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Manages quick launch shortcuts by:
+ * <li> Keeping the local copy in sync with the database (this is an observer)
+ * <li> Returning a shortcut-matching intent to clients
+ * <li> Returning particular kind of application intent by special key.
+ */
+class ModifierShortcutManager {
+    private static final String TAG = "ShortcutManager";
+
+    private static final String TAG_BOOKMARKS = "bookmarks";
+    private static final String TAG_BOOKMARK = "bookmark";
+
+    private static final String ATTRIBUTE_PACKAGE = "package";
+    private static final String ATTRIBUTE_CLASS = "class";
+    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+    private static final String ATTRIBUTE_CATEGORY = "category";
+    private static final String ATTRIBUTE_SHIFT = "shift";
+
+    private final SparseArray<ShortcutInfo> mIntentShortcuts = new SparseArray<>();
+    private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>();
+
+    private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
+
+    /* Table of Application Launch keys.  Maps from key codes to intent categories.
+     *
+     * These are special keys that are used to launch particular kinds of applications,
+     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
+     * usage page.  We don't support quite that many yet...
+     */
+    static SparseArray<String> sApplicationLaunchKeyCategories;
+    static {
+        sApplicationLaunchKeyCategories = new SparseArray<String>();
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
+    }
+
+    private final Context mContext;
+    private boolean mSearchKeyShortcutPending = false;
+    private boolean mConsumeSearchKeyUp = true;
+
+    ModifierShortcutManager(Context context) {
+        mContext = context;
+        loadShortcuts();
+    }
+
+    /**
+     * Gets the shortcut intent for a given keycode+modifier. Make sure you
+     * strip whatever modifier is used for invoking shortcuts (for example,
+     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
+     * 'Sym' bit from the modifiers before calling this method.
+     * <p>
+     * This will first try an exact match (with modifiers), and then try a
+     * match without modifiers (primary character on a key).
+     *
+     * @param kcm The key character map of the device on which the key was pressed.
+     * @param keyCode The key code.
+     * @param metaState The meta state, omitting any modifiers that were used
+     * to invoke the shortcut.
+     * @return The intent that matches the shortcut, or null if not found.
+     */
+    private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
+        ShortcutInfo shortcut = null;
+
+        // If the Shift key is pressed, then search for the shift shortcuts.
+        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
+        SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts;
+
+        // First try the exact keycode (with modifiers).
+        int shortcutChar = kcm.get(keyCode, metaState);
+        if (shortcutChar != 0) {
+            shortcut = shortcutMap.get(shortcutChar);
+        }
+
+        // Next try the primary character on that key.
+        if (shortcut == null) {
+            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+            if (shortcutChar != 0) {
+                shortcut = shortcutMap.get(shortcutChar);
+            }
+        }
+
+        return (shortcut != null) ? shortcut.intent : null;
+    }
+
+    private void loadShortcuts() {
+        PackageManager packageManager = mContext.getPackageManager();
+        try {
+            XmlResourceParser parser = mContext.getResources().getXml(
+                    com.android.internal.R.xml.bookmarks);
+            XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                if (!TAG_BOOKMARK.equals(parser.getName())) {
+                    break;
+                }
+
+                String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
+                String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
+                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
+                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+                String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
+
+                if (TextUtils.isEmpty(shortcutName)) {
+                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
+                    continue;
+                }
+
+                final int shortcutChar = shortcutName.charAt(0);
+                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
+
+                final Intent intent;
+                final String title;
+                if (packageName != null && className != null) {
+                    ActivityInfo info = null;
+                    ComponentName componentName = new ComponentName(packageName, className);
+                    try {
+                        info = packageManager.getActivityInfo(componentName,
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        String[] packages = packageManager.canonicalToCurrentPackageNames(
+                                new String[] { packageName });
+                        componentName = new ComponentName(packages[0], className);
+                        try {
+                            info = packageManager.getActivityInfo(componentName,
+                                    PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                        } catch (PackageManager.NameNotFoundException e1) {
+                            Log.w(TAG, "Unable to add bookmark: " + packageName
+                                    + "/" + className, e);
+                            continue;
+                        }
+                    }
+
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
+                    intent.setComponent(componentName);
+                    title = info.loadLabel(packageManager).toString();
+                } else if (categoryName != null) {
+                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+                    title = "";
+                } else {
+                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
+                            + ": missing package/class or category attributes");
+                    continue;
+                }
+
+                ShortcutInfo shortcut = new ShortcutInfo(title, intent);
+                if (isShiftShortcut) {
+                    mShiftShortcuts.put(shortcutChar, shortcut);
+                } else {
+                    mIntentShortcuts.put(shortcutChar, shortcut);
+                }
+            }
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        } catch (IOException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        }
+    }
+
+    void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
+            throws RemoteException {
+        IShortcutService service = mShortcutKeyServices.get(shortcutCode);
+        if (service != null && service.asBinder().pingBinder()) {
+            throw new RemoteException("Key already exists.");
+        }
+
+        mShortcutKeyServices.put(shortcutCode, shortcutService);
+    }
+
+    /**
+     * Handle the shortcut to {@link IShortcutService}
+     * @param keyCode The key code of the event.
+     * @param metaState The meta key modifier state.
+     * @return True if invoked the shortcut, otherwise false.
+     */
+    private boolean handleShortcutService(int keyCode, int metaState) {
+        long shortcutCode = keyCode;
+        if ((metaState & KeyEvent.META_CTRL_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
+        }
+
+        if ((metaState & KeyEvent.META_ALT_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
+        }
+
+        if ((metaState & KeyEvent.META_SHIFT_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
+        }
+
+        if ((metaState & KeyEvent.META_META_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE;
+        }
+
+        IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
+        if (shortcutService != null) {
+            try {
+                shortcutService.notifyShortcutKeyPressed(shortcutCode);
+            } catch (RemoteException e) {
+                mShortcutKeyServices.delete(shortcutCode);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handle the shortcut to {@link Intent}
+     *
+     * @param kcm the {@link KeyCharacterMap} associated with the keyboard device.
+     * @param keyCode The key code of the event.
+     * @param metaState The meta key modifier state.
+     * @return True if invoked the shortcut, otherwise false.
+     */
+    private boolean handleIntentShortcut(KeyCharacterMap kcm, int keyCode, int metaState) {
+        // Shortcuts are invoked through Search+key, so intercept those here
+        // Any printing key that is chorded with Search should be consumed
+        // even if no shortcut was invoked.  This prevents text from being
+        // inadvertently inserted when using a keyboard that has built-in macro
+        // shortcut keys (that emit Search+x) and some of them are not registered.
+        if (mSearchKeyShortcutPending) {
+            if (kcm.isPrintingKey(keyCode)) {
+                mConsumeSearchKeyUp = true;
+                mSearchKeyShortcutPending = false;
+            } else {
+                return false;
+            }
+        } else if ((metaState & KeyEvent.META_META_MASK) != 0) {
+            // Invoke shortcuts using Meta.
+            metaState &= ~KeyEvent.META_META_MASK;
+        } else {
+            // Handle application launch keys.
+            String category = sApplicationLaunchKeyCategories.get(keyCode);
+            if (category != null) {
+                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                try {
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                } catch (ActivityNotFoundException ex) {
+                    Slog.w(TAG, "Dropping application launch key because "
+                            + "the activity to which it is registered was not found: "
+                            + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
+                            + " category=" + category, ex);
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        final Intent shortcutIntent = getIntent(kcm, keyCode, metaState);
+        if (shortcutIntent != null) {
+            shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            try {
+                mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+            } catch (ActivityNotFoundException ex) {
+                Slog.w(TAG, "Dropping shortcut key combination because "
+                        + "the activity to which it is registered was not found: "
+                        + "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode), ex);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handle the shortcut from {@link KeyEvent}
+     *
+     * @param event Description of the key event.
+     * @return True if invoked the shortcut, otherwise false.
+     */
+    boolean interceptKey(KeyEvent event) {
+        if (event.getRepeatCount() != 0) {
+            return false;
+        }
+
+        final int metaState = event.getModifiers();
+        final int keyCode = event.getKeyCode();
+        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                mSearchKeyShortcutPending = true;
+                mConsumeSearchKeyUp = false;
+            } else {
+                mSearchKeyShortcutPending = false;
+                if (mConsumeSearchKeyUp) {
+                    mConsumeSearchKeyUp = false;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return false;
+        }
+
+        final KeyCharacterMap kcm = event.getKeyCharacterMap();
+        if (handleIntentShortcut(kcm, keyCode, metaState)) {
+            return true;
+        }
+
+        if (handleShortcutService(keyCode, metaState)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static final class ShortcutInfo {
+        public final String title;
+        public final Intent intent;
+
+        ShortcutInfo(String title, Intent intent) {
+            this.title = title;
+            this.intent = intent;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1b192e4..bce218f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -73,8 +73,6 @@
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
 
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -165,7 +163,6 @@
 import android.speech.RecognizerIntent;
 import android.telecom.TelecomManager;
 import android.util.Log;
-import android.util.LongSparseArray;
 import android.util.MutableBoolean;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -320,29 +317,6 @@
      */
     private boolean mKeyguardDrawnOnce;
 
-    /* Table of Application Launch keys.  Maps from key codes to intent categories.
-     *
-     * These are special keys that are used to launch particular kinds of applications,
-     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
-     * usage page.  We don't support quite that many yet...
-     */
-    static SparseArray<String> sApplicationLaunchKeyCategories;
-    static {
-        sApplicationLaunchKeyCategories = new SparseArray<String>();
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
-    }
-
     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
 
@@ -421,8 +395,6 @@
     boolean mSafeMode;
     private WindowState mKeyguardCandidate = null;
 
-    private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
-
     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
     // This is for car dock and this is updated from resource.
     private boolean mEnableCarDockHomeCapture = true;
@@ -458,6 +430,7 @@
     volatile boolean mPowerKeyHandled;
     volatile boolean mBackKeyHandled;
     volatile boolean mBeganFromNonInteractive;
+    volatile int mPowerKeyPressCounter;
     volatile boolean mEndCallKeyHandled;
     volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
     volatile boolean mGoingToSleep;
@@ -498,6 +471,7 @@
     boolean mHasSoftInput = false;
     boolean mHapticTextHandleEnabled;
     boolean mUseTvRouting;
+    int mVeryLongPressTimeout;
     boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
     MetricsLogger mLogger;
     boolean mWakeOnDpadKeyPress;
@@ -516,8 +490,6 @@
     Intent mCarDockIntent;
     Intent mDeskDockIntent;
     Intent mVrHeadsetHomeIntent;
-    boolean mSearchKeyShortcutPending;
-    boolean mConsumeSearchKeyUp;
     boolean mPendingMetaAction;
     boolean mPendingCapsLockToggle;
 
@@ -578,7 +550,7 @@
     private static final int BRIGHTNESS_STEPS = 10;
 
     SettingsObserver mSettingsObserver;
-    ShortcutManager mShortcutManager;
+    ModifierShortcutManager mModifierShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
     PowerManager.WakeLock mPowerKeyWakeLock;
     boolean mHavePendingMediaKeyRepeatWithWakeLock;
@@ -595,13 +567,14 @@
     private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator
             = new LogDecelerateInterpolator(100, 0);
 
+    private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
+
     private boolean mPerDisplayFocusEnabled = false;
     private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
 
     private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;
 
     private KeyCombinationManager mKeyCombinationManager;
-    private SingleKeyGestureDetector mSingleKeyGestureDetector;
 
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
     private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
@@ -612,7 +585,10 @@
     private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
     private static final int MSG_HIDE_BOOT_MESSAGE = 11;
     private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
+    private static final int MSG_POWER_DELAYED_PRESS = 13;
+    private static final int MSG_POWER_LONG_PRESS = 14;
     private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 15;
+    private static final int MSG_BACK_LONG_PRESS = 16;
     private static final int MSG_ACCESSIBILITY_SHORTCUT = 17;
     private static final int MSG_BUGREPORT_TV = 18;
     private static final int MSG_ACCESSIBILITY_TV = 19;
@@ -620,7 +596,8 @@
     private static final int MSG_SYSTEM_KEY_PRESS = 21;
     private static final int MSG_HANDLE_ALL_APPS = 22;
     private static final int MSG_LAUNCH_ASSIST = 23;
-    private static final int MSG_RINGER_TOGGLE_CHORD = 24;
+    private static final int MSG_POWER_VERY_LONG_PRESS = 25;
+    private static final int MSG_RINGER_TOGGLE_CHORD = 26;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -661,9 +638,22 @@
                 case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
                     launchVoiceAssistWithWakeLock();
                     break;
+                case MSG_POWER_DELAYED_PRESS:
+                    powerPress((Long) msg.obj, msg.arg1 != 0, msg.arg2);
+                    finishPowerKeyPress();
+                    break;
+                case MSG_POWER_LONG_PRESS:
+                    powerLongPress((Long) msg.obj /* eventTime */);
+                    break;
+                case MSG_POWER_VERY_LONG_PRESS:
+                    powerVeryLongPress();
+                    break;
                 case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
                     showPictureInPictureMenuInternal();
                     break;
+                case MSG_BACK_LONG_PRESS:
+                    backLongPress();
+                    break;
                 case MSG_ACCESSIBILITY_SHORTCUT:
                     accessibilityShortcutActivated();
                     break;
@@ -774,6 +764,13 @@
         }
     };
 
+    private Runnable mPossibleVeryLongPressReboot = new Runnable() {
+        @Override
+        public void run() {
+            mActivityManagerInternal.prepareForPossibleShutdown();
+        }
+    };
+
     private void handleRingerChordGesture() {
         if (mRingerToggleChord == VOLUME_HUSH_OFF) {
             return;
@@ -813,13 +810,28 @@
         }
     }
 
+    private void interceptBackKeyDown() {
+        mLogger.count("key_back_down", 1);
+        // Reset back key state for long press
+        mBackKeyHandled = false;
+
+        if (hasLongPressOnBackBehavior()) {
+            Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
+            msg.setAsynchronous(true);
+            mHandler.sendMessageDelayed(msg,
+                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+        }
+    }
 
     // returns true if the key was handled and should not be passed to the user
-    private boolean backKeyPress() {
-        mLogger.count("key_back_press", 1);
+    private boolean interceptBackKeyUp(KeyEvent event) {
+        mLogger.count("key_back_up", 1);
         // Cache handled state
         boolean handled = mBackKeyHandled;
 
+        // Reset back long press state
+        cancelPendingBackKeyAction();
+
         if (mHasFeatureWatch) {
             TelecomManager telecomManager = getTelecommService();
 
@@ -841,9 +853,10 @@
             }
         }
 
-        if (mAutofillManagerInternal != null) {
+        if (mAutofillManagerInternal != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
             mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_BACK_KEY_TO_AUTOFILL));
         }
+
         return handled;
     }
 
@@ -853,6 +866,11 @@
             mPowerKeyWakeLock.acquire();
         }
 
+        // Cancel multi-press detection timeout.
+        if (mPowerKeyPressCounter != 0) {
+            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
+        }
+
         mWindowManagerFuncs.onPowerKeyDown(interactive);
 
         // Stop ringing or end call if configured to do so when power is pressed.
@@ -874,20 +892,71 @@
 
         final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event);
 
+        GestureLauncherService gestureService = LocalServices.getService(
+                GestureLauncherService.class);
+        boolean gesturedServiceIntercepted = false;
+        if (gestureService != null) {
+            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
+                    mTmpBoolean);
+            if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
+                mCameraGestureTriggeredDuringGoingToSleep = true;
+            }
+        }
+
         // Inform the StatusBar; but do not allow it to consume the event.
         sendSystemKeyToStatusBarAsync(event.getKeyCode());
 
+        schedulePossibleVeryLongPressReboot();
+
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
-        mPowerKeyHandled = mPowerKeyHandled || hungUp
+        mPowerKeyHandled = hungUp || gesturedServiceIntercepted
                 || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
         if (!mPowerKeyHandled) {
-            if (!interactive) {
+            if (interactive) {
+                // When interactive, we're already awake.
+                // Wait for a long press or for the button to be released to decide what to do.
+                if (hasLongPressOnPowerBehavior()) {
+                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                        powerLongPress(event.getEventTime());
+                    } else {
+                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
+                                event.getEventTime());
+                        msg.setAsynchronous(true);
+                        mHandler.sendMessageDelayed(msg,
+                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+
+                        if (hasVeryLongPressOnPowerBehavior()) {
+                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+                            longMsg.setAsynchronous(true);
+                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+                        }
+                    }
+                }
+            } else {
                 wakeUpFromPowerKey(event.getDownTime());
+
                 if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
+                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                        powerLongPress(event.getEventTime());
+                    } else {
+                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
+                                event.getEventTime());
+                        msg.setAsynchronous(true);
+                        mHandler.sendMessageDelayed(msg,
+                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+
+                        if (hasVeryLongPressOnPowerBehavior()) {
+                            Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+                            longMsg.setAsynchronous(true);
+                            mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+                        }
+                    }
+
                     mBeganFromNonInteractive = true;
                 } else {
                     final int maxCount = getMaxMultiPressPowerCount();
+
                     if (maxCount <= 1) {
                         mPowerKeyHandled = true;
                     } else {
@@ -895,38 +964,68 @@
                     }
                 }
             }
-        } else {
-            // handled by another power key policy.
-            if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
-                mSingleKeyGestureDetector.reset();
-            }
         }
     }
 
     private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
         final boolean handled = canceled || mPowerKeyHandled;
+        cancelPendingPowerKeyAction();
 
         if (!handled) {
             if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
                 // Abort possibly stuck animations only when power key up without long press case.
                 mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
             }
-        } else {
-            // handled by single key or another power key policy.
-            mSingleKeyGestureDetector.reset();
-            finishPowerKeyPress();
+
+            // Figure out how to handle the key now that it has been released.
+            mPowerKeyPressCounter += 1;
+
+            final int maxCount = getMaxMultiPressPowerCount();
+            final long eventTime = event.getDownTime();
+            if (mPowerKeyPressCounter < maxCount) {
+                // This could be a multi-press.  Wait a little bit longer to confirm.
+                // Continue holding the wake lock.
+                Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
+                        interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
+                return;
+            }
+
+            // No other actions.  Handle it immediately.
+            powerPress(eventTime, interactive, mPowerKeyPressCounter);
         }
 
+        // Done.  Reset our state.
+        finishPowerKeyPress();
     }
 
     private void finishPowerKeyPress() {
         mBeganFromNonInteractive = false;
-        mPowerKeyHandled = false;
+        mPowerKeyPressCounter = 0;
         if (mPowerKeyWakeLock.isHeld()) {
             mPowerKeyWakeLock.release();
         }
     }
 
+    private void cancelPendingPowerKeyAction() {
+        if (!mPowerKeyHandled) {
+            mPowerKeyHandled = true;
+            mHandler.removeMessages(MSG_POWER_LONG_PRESS);
+        }
+        if (hasVeryLongPressOnPowerBehavior()) {
+            mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
+        }
+        cancelPossibleVeryLongPressReboot();
+    }
+
+    private void cancelPendingBackKeyAction() {
+        if (!mBackKeyHandled) {
+            mBackKeyHandled = true;
+            mHandler.removeMessages(MSG_BACK_LONG_PRESS);
+        }
+    }
+
     private void powerPress(long eventTime, boolean interactive, int count) {
         if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) {
             Slog.i(TAG, "Suppressed redundant power key press while "
@@ -1077,7 +1176,6 @@
 
     private void powerLongPress(long eventTime) {
         final int behavior = getResolvedLongPressOnPowerBehavior();
-
         switch (behavior) {
             case LONG_PRESS_POWER_NOTHING:
                 break;
@@ -1646,7 +1744,7 @@
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
-        mShortcutManager = new ShortcutManager(context);
+        mModifierShortcutManager = new ModifierShortcutManager(context);
         mUiMode = context.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultUiModeType);
         mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
@@ -1716,6 +1814,8 @@
                 com.android.internal.R.integer.config_triplePressOnPowerBehavior);
         mShortPressOnSleepBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shortPressOnSleepBehavior);
+        mVeryLongPressTimeout = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_veryLongPressTimeout);
         mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
 
@@ -1809,7 +1909,6 @@
                     }
                 });
         initKeyCombinationRules();
-        initSingleKeyGestureRules();
     }
 
     private void initKeyCombinationRules() {
@@ -1822,7 +1921,7 @@
                     new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
                         @Override
                         void execute() {
-                            mPowerKeyHandled = true;
+                            cancelPendingPowerKeyAction();
                             interceptScreenshotChord();
                         }
                         @Override
@@ -1857,7 +1956,7 @@
                     }
                     @Override
                     void execute() {
-                        mPowerKeyHandled = true;
+                        cancelPendingPowerKeyAction();
                         interceptRingerToggleChord();
                     }
                     @Override
@@ -1871,7 +1970,7 @@
                     new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) {
                         @Override
                         void execute() {
-                            mBackKeyHandled = true;
+                            cancelPendingBackKeyAction();
                             interceptAccessibilityGestureTv();
                         }
 
@@ -1885,7 +1984,7 @@
                     new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) {
                         @Override
                         void execute() {
-                            mBackKeyHandled = true;
+                            cancelPendingBackKeyAction();
                             interceptBugreportGestureTv();
                         }
 
@@ -1898,84 +1997,6 @@
     }
 
     /**
-     * Rule for single power key gesture.
-     */
-    private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
-        PowerKeyRule(int gestures) {
-            super(KEYCODE_POWER, gestures);
-        }
-
-        @Override
-        int getMaxMultiPressCount() {
-            return getMaxMultiPressPowerCount();
-        }
-
-        @Override
-        void onPress(long downTime) {
-            powerPress(downTime, true, 1 /*count*/);
-            finishPowerKeyPress();
-        }
-
-        @Override
-        void onLongPress(long downTime) {
-            powerLongPress(downTime);
-        }
-
-        @Override
-        void onVeryLongPress(long downTime) {
-            mActivityManagerInternal.prepareForPossibleShutdown();
-            powerVeryLongPress();
-        }
-
-        @Override
-        void onMultiPress(long downTime, int count) {
-            powerPress(downTime, true, count);
-            finishPowerKeyPress();
-        }
-    }
-
-    /**
-     * Rule for single back key gesture.
-     */
-    private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
-        BackKeyRule(int gestures) {
-            super(KEYCODE_BACK, gestures);
-        }
-
-        @Override
-        int getMaxMultiPressCount() {
-            return 1;
-        }
-
-        @Override
-        void onPress(long downTime) {
-            mBackKeyHandled |= backKeyPress();
-        }
-
-        @Override
-        void onLongPress(long downTime) {
-            backLongPress();
-        }
-    }
-
-    private void initSingleKeyGestureRules() {
-        mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext);
-
-        int powerKeyGestures = 0;
-        if (hasVeryLongPressOnPowerBehavior()) {
-            powerKeyGestures |= KEY_VERYLONGPRESS;
-        }
-        if (hasLongPressOnPowerBehavior()) {
-            powerKeyGestures |= KEY_LONGPRESS;
-        }
-        mSingleKeyGestureDetector.addRule(new PowerKeyRule(powerKeyGestures));
-
-        if (hasLongPressOnBackBehavior()) {
-            mSingleKeyGestureDetector.addRule(new BackKeyRule(KEY_LONGPRESS));
-        }
-    }
-
-    /**
      * Read values from config.xml that may be overridden depending on
      * the configuration of the device.
      * eg. Disable long press on home goes to recents on sw600dp.
@@ -2525,6 +2546,15 @@
             mPendingCapsLockToggle = false;
         }
 
+        if (isUserSetupComplete() && !keyguardOn) {
+            if (mModifierShortcutManager.interceptKey(event)) {
+                dismissKeyboardShortcutsMenu();
+                mPendingMetaAction = false;
+                mPendingCapsLockToggle = false;
+                return key_consumed;
+            }
+        }
+
         switch(keyCode) {
             case KeyEvent.KEYCODE_HOME:
                 // First we always handle the home key here, so applications
@@ -2550,20 +2580,6 @@
                     }
                 }
                 break;
-            case  KeyEvent.KEYCODE_SEARCH:
-                if (down) {
-                    if (repeatCount == 0) {
-                        mSearchKeyShortcutPending = true;
-                        mConsumeSearchKeyUp = false;
-                    }
-                } else {
-                    mSearchKeyShortcutPending = false;
-                    if (mConsumeSearchKeyUp) {
-                        mConsumeSearchKeyUp = false;
-                        return key_consumed;
-                    }
-                }
-                return 0;
             case KeyEvent.KEYCODE_APP_SWITCH:
                 if (!keyguardOn) {
                     if (down && repeatCount == 0) {
@@ -2771,114 +2787,11 @@
                 break;
         }
 
-        // Shortcuts are invoked through Search+key, so intercept those here
-        // Any printing key that is chorded with Search should be consumed
-        // even if no shortcut was invoked.  This prevents text from being
-        // inadvertently inserted when using a keyboard that has built-in macro
-        // shortcut keys (that emit Search+x) and some of them are not registered.
-        if (mSearchKeyShortcutPending) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            if (kcm.isPrintingKey(keyCode)) {
-                mConsumeSearchKeyUp = true;
-                mSearchKeyShortcutPending = false;
-                if (down && repeatCount == 0 && !keyguardOn) {
-                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
-                    if (shortcutIntent != null) {
-                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        try {
-                            startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
-                            dismissKeyboardShortcutsMenu();
-                        } catch (ActivityNotFoundException ex) {
-                            Slog.w(TAG, "Dropping shortcut key combination because "
-                                    + "the activity to which it is registered was not found: "
-                                    + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex);
-                        }
-                    } else {
-                        Slog.i(TAG, "Dropping unregistered shortcut key combination: "
-                                + "SEARCH+" + KeyEvent.keyCodeToString(keyCode));
-                    }
-                }
-                return key_consumed;
-            }
-        }
-
-        // Invoke shortcuts using Meta.
-        if (down && repeatCount == 0 && !keyguardOn
-                && (metaState & KeyEvent.META_META_ON) != 0) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            if (kcm.isPrintingKey(keyCode)) {
-                Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
-                        metaState & ~(KeyEvent.META_META_ON
-                                | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
-                if (shortcutIntent != null) {
-                    shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
-                        dismissKeyboardShortcutsMenu();
-                    } catch (ActivityNotFoundException ex) {
-                        Slog.w(TAG, "Dropping shortcut key combination because "
-                                + "the activity to which it is registered was not found: "
-                                + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
-                    }
-                    return key_consumed;
-                }
-            }
-        }
-
-        // Handle application launch keys.
-        if (down && repeatCount == 0 && !keyguardOn) {
-            String category = sApplicationLaunchKeyCategories.get(keyCode);
-            if (category != null) {
-                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                try {
-                    startActivityAsUser(intent, UserHandle.CURRENT);
-                    dismissKeyboardShortcutsMenu();
-                } catch (ActivityNotFoundException ex) {
-                    Slog.w(TAG, "Dropping application launch key because "
-                            + "the activity to which it is registered was not found: "
-                            + "keyCode=" + keyCode + ", category=" + category, ex);
-                }
-                return key_consumed;
-            }
-        }
-
         if (isValidGlobalKey(keyCode)
                 && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
             return key_consumed;
         }
 
-        if (down) {
-            long shortcutCode = keyCode;
-            if (event.isCtrlPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
-            }
-
-            if (event.isAltPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
-            }
-
-            if (event.isShiftPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
-            }
-
-            if (event.isMetaPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE;
-            }
-
-            IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
-            if (shortcutService != null) {
-                try {
-                    if (isUserSetupComplete()) {
-                        shortcutService.notifyShortcutKeyPressed(shortcutCode);
-                    }
-                } catch (RemoteException e) {
-                    mShortcutKeyServices.delete(shortcutCode);
-                }
-                return key_consumed;
-            }
-        }
-
         // Reserve all the META modifier combos for system behavior
         if ((metaState & KeyEvent.META_META_ON) != 0) {
             return key_consumed;
@@ -3064,12 +2977,7 @@
     public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
             throws RemoteException {
         synchronized (mLock) {
-            IShortcutService service = mShortcutKeyServices.get(shortcutCode);
-            if (service != null && service.asBinder().pingBinder()) {
-                throw new RemoteException("Key already exists.");
-            }
-
-            mShortcutKeyServices.put(shortcutCode, shortcutService);
+            mModifierShortcutManager.registerShortcutKey(shortcutCode, shortcutService);
         }
     }
 
@@ -3519,21 +3427,8 @@
             return result;
         }
 
-        // Alternate TV power to power key for Android TV device.
-        final HdmiControlManager hdmiControlManager = getHdmiControlManager();
-        if (keyCode == KeyEvent.KEYCODE_TV_POWER && mHasFeatureLeanback
-                && (hdmiControlManager == null || !hdmiControlManager.shouldHandleTvPowerKey())) {
-            event = KeyEvent.obtain(
-                    event.getDownTime(), event.getEventTime(),
-                    event.getAction(), KeyEvent.KEYCODE_POWER,
-                    event.getRepeatCount(), event.getMetaState(),
-                    event.getDeviceId(), event.getScanCode(),
-                    event.getFlags(), event.getSource(), event.getDisplayId(), null);
-            return interceptKeyBeforeQueueing(event, policyFlags);
-        }
-
         if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-            handleKeyGesture(event, interactive);
+            mKeyCombinationManager.interceptKey(event, interactive);
         }
 
         // Enable haptics if down and virtual key without multiple repetitions. If this is a hard
@@ -3548,13 +3443,12 @@
         switch (keyCode) {
             case KeyEvent.KEYCODE_BACK: {
                 if (down) {
-                    mBackKeyHandled = false;
+                    interceptBackKeyDown();
                 } else {
-                    if (!hasLongPressOnBackBehavior()) {
-                        mBackKeyHandled |= backKeyPress();
-                    }
+                    boolean handled = interceptBackKeyUp(event);
+
                     // Don't pass back press to app if we've already handled it via long press
-                    if (mBackKeyHandled) {
+                    if (handled) {
                         result &= ~ACTION_PASS_TO_USER;
                     }
                 }
@@ -3666,17 +3560,33 @@
             case KeyEvent.KEYCODE_TV_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
-                if (down && hdmiControlManager != null) {
-                    hdmiControlManager.toggleAndFollowTvPower();
+                HdmiControlManager hdmiControlManager = getHdmiControlManager();
+                if (hdmiControlManager != null && hdmiControlManager.shouldHandleTvPowerKey()) {
+                    if (down) {
+                        hdmiControlManager.toggleAndFollowTvPower();
+                    }
+                } else if (mHasFeatureLeanback) {
+                    KeyEvent fallbackEvent = KeyEvent.obtain(
+                            event.getDownTime(), event.getEventTime(),
+                            event.getAction(), KeyEvent.KEYCODE_POWER,
+                            event.getRepeatCount(), event.getMetaState(),
+                            event.getDeviceId(), event.getScanCode(),
+                            event.getFlags(), event.getSource(), event.getDisplayId(), null);
+                    if (down) {
+                        interceptPowerKeyDown(fallbackEvent, interactive);
+                    } else {
+                        interceptPowerKeyUp(fallbackEvent, interactive, canceled);
+                    }
                 }
+                // Ignore this key for any device that is not connected to a TV via HDMI and
+                // not an Android TV device.
                 break;
             }
 
             case KeyEvent.KEYCODE_POWER: {
                 EventLogTags.writeInterceptPower(
                         KeyEvent.actionToString(event.getAction()),
-                        mPowerKeyHandled ? 1 : 0,
-                        mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
+                        mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
                 // Any activity on the power button stops the accessibility shortcut
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
@@ -3857,43 +3767,6 @@
         return result;
     }
 
-    private void handleKeyGesture(KeyEvent event, boolean interactive) {
-        if (mKeyCombinationManager.interceptKey(event, interactive)) {
-            // handled by combo keys manager.
-            mSingleKeyGestureDetector.reset();
-            return;
-        }
-
-        if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
-            mPowerKeyHandled = handleCameraGesture(event, interactive);
-            if (mPowerKeyHandled) {
-                // handled by camera gesture.
-                mSingleKeyGestureDetector.reset();
-                return;
-            }
-        }
-
-        mSingleKeyGestureDetector.interceptKey(event);
-    }
-
-    // The camera gesture will be detected by GestureLauncherService.
-    private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
-        // camera gesture.
-        GestureLauncherService gestureService = LocalServices.getService(
-                GestureLauncherService.class);
-        if (gestureService == null) {
-            return false;
-        }
-
-        final MutableBoolean outLaunched = new MutableBoolean(false);
-        final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
-                interactive, outLaunched);
-        if (outLaunched.value && mRequestedOrGoingToSleep) {
-            mCameraGestureTriggeredDuringGoingToSleep = true;
-        }
-        return gesturedServiceIntercepted;
-    }
-
     /**
      * Handle statusbar expansion events.
      * @param event
@@ -4893,6 +4766,15 @@
         }
     }
 
+    private void schedulePossibleVeryLongPressReboot() {
+        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+        mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
+    }
+
+    private void cancelPossibleVeryLongPressReboot() {
+        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+    }
+
     // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
     private void updateScreenOffSleepToken(boolean acquire) {
         if (acquire) {
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
deleted file mode 100644
index ab404db..0000000
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.XmlResourceParser;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Manages quick launch shortcuts by:
- * <li> Keeping the local copy in sync with the database (this is an observer)
- * <li> Returning a shortcut-matching intent to clients
- */
-class ShortcutManager {
-    private static final String TAG = "ShortcutManager";
-
-    private static final String TAG_BOOKMARKS = "bookmarks";
-    private static final String TAG_BOOKMARK = "bookmark";
-
-    private static final String ATTRIBUTE_PACKAGE = "package";
-    private static final String ATTRIBUTE_CLASS = "class";
-    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
-    private static final String ATTRIBUTE_CATEGORY = "category";
-    private static final String ATTRIBUTE_SHIFT = "shift";
-
-    private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
-    private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>();
-
-    private final Context mContext;
-    
-    public ShortcutManager(Context context) {
-        mContext = context;
-        loadShortcuts();
-    }
-
-    /**
-     * Gets the shortcut intent for a given keycode+modifier. Make sure you
-     * strip whatever modifier is used for invoking shortcuts (for example,
-     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
-     * 'Sym' bit from the modifiers before calling this method.
-     * <p>
-     * This will first try an exact match (with modifiers), and then try a
-     * match without modifiers (primary character on a key).
-     * 
-     * @param kcm The key character map of the device on which the key was pressed.
-     * @param keyCode The key code.
-     * @param metaState The meta state, omitting any modifiers that were used
-     * to invoke the shortcut.
-     * @return The intent that matches the shortcut, or null if not found.
-     */
-    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
-        ShortcutInfo shortcut = null;
-
-        // If the Shift key is pressed, then search for the shift shortcuts.
-        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
-        SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts;
-
-        // First try the exact keycode (with modifiers).
-        int shortcutChar = kcm.get(keyCode, metaState);
-        if (shortcutChar != 0) {
-            shortcut = shortcutMap.get(shortcutChar);
-        }
-
-        // Next try the primary character on that key.
-        if (shortcut == null) {
-            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
-            if (shortcutChar != 0) {
-                shortcut = shortcutMap.get(shortcutChar);
-            }
-        }
-
-        return (shortcut != null) ? shortcut.intent : null;
-    }
-
-    private void loadShortcuts() {
-        PackageManager packageManager = mContext.getPackageManager();
-        try {
-            XmlResourceParser parser = mContext.getResources().getXml(
-                    com.android.internal.R.xml.bookmarks);
-            XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-
-                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                    break;
-                }
-
-                if (!TAG_BOOKMARK.equals(parser.getName())) {
-                    break;
-                }
-
-                String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
-                String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
-                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
-                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
-                String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
-
-                if (TextUtils.isEmpty(shortcutName)) {
-                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
-                    continue;
-                }
-
-                final int shortcutChar = shortcutName.charAt(0);
-                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
-
-                final Intent intent;
-                final String title;
-                if (packageName != null && className != null) {
-                    ActivityInfo info = null;
-                    ComponentName componentName = new ComponentName(packageName, className);
-                    try {
-                        info = packageManager.getActivityInfo(componentName,
-                                PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
-                    } catch (PackageManager.NameNotFoundException e) {
-                        String[] packages = packageManager.canonicalToCurrentPackageNames(
-                                new String[] { packageName });
-                        componentName = new ComponentName(packages[0], className);
-                        try {
-                            info = packageManager.getActivityInfo(componentName,
-                                    PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
-                        } catch (PackageManager.NameNotFoundException e1) {
-                            Log.w(TAG, "Unable to add bookmark: " + packageName
-                                    + "/" + className, e);
-                            continue;
-                        }
-                    }
-
-                    intent = new Intent(Intent.ACTION_MAIN);
-                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
-                    intent.setComponent(componentName);
-                    title = info.loadLabel(packageManager).toString();
-                } else if (categoryName != null) {
-                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
-                    title = "";
-                } else {
-                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
-                            + ": missing package/class or category attributes");
-                    continue;
-                }
-
-                ShortcutInfo shortcut = new ShortcutInfo(title, intent);
-                if (isShiftShortcut) {
-                    mShiftShortcuts.put(shortcutChar, shortcut);
-                } else {
-                    mShortcuts.put(shortcutChar, shortcut);
-                }
-            }
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "Got exception parsing bookmarks.", e);
-        } catch (IOException e) {
-            Log.w(TAG, "Got exception parsing bookmarks.", e);
-        }
-    }
-
-    private static final class ShortcutInfo {
-        public final String title;
-        public final Intent intent;
-
-        public ShortcutInfo(String title, Intent intent) {
-            this.title = title;
-            this.intent = intent;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
deleted file mode 100644
index 3dafb0ce..0000000
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-
-/**
- * Detect single key gesture: press, long press, very long press and multi press.
- *
- * Call {@link #reset} if current {@link KeyEvent} has been handled by another policy
- */
-
-public final class SingleKeyGestureDetector {
-    private static final String TAG = "SingleKeyGesture";
-    private static final boolean DEBUG = false;
-
-    private static final int MSG_KEY_LONG_PRESS = 0;
-    private static final int MSG_KEY_VERY_LONG_PRESS = 1;
-    private static final int MSG_KEY_DELAYED_PRESS = 2;
-
-    private final long mLongPressTimeout;
-    private final long mVeryLongPressTimeout;
-
-    private volatile int mKeyPressCounter;
-
-    private final ArrayList<SingleKeyRule> mRules = new ArrayList();
-    private SingleKeyRule mActiveRule = null;
-
-    // Key code of current key down event, reset when key up.
-    private int mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
-    private volatile boolean mHandledByLongPress = false;
-    private final Handler mHandler;
-    private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
-
-
-    /** Supported gesture flags */
-    public static final int KEY_LONGPRESS = 1 << 1;
-    public static final int KEY_VERYLONGPRESS = 1 << 2;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "KEY_" }, value = {
-            KEY_LONGPRESS,
-            KEY_VERYLONGPRESS,
-    })
-    public @interface KeyGestureFlag {}
-
-    /**
-     *  Rule definition for single keys gesture.
-     *  E.g : define power key.
-     *  <pre class="prettyprint">
-     *  SingleKeyRule rule =
-     *      new SingleKeyRule(KEYCODE_POWER, KEY_LONGPRESS|KEY_VERYLONGPRESS) {
-     *           int getMaxMultiPressCount() { // maximum multi press count. }
-     *           void onPress(long downTime) { // short press behavior. }
-     *           void onLongPress() { // long press behavior. }
-     *           void onVeryLongPress() { // very long press behavior. }
-     *           void onMultiPress(long downTime, int count) { // multi press behavior.  }
-     *       };
-     *  </pre>
-     */
-    abstract static class SingleKeyRule {
-        private final int mKeyCode;
-        private final int mSupportedGestures;
-
-        SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) {
-            mKeyCode = keyCode;
-            mSupportedGestures = supportedGestures;
-        }
-
-        /**
-         *  True if the rule could intercept the key.
-         */
-        private boolean shouldInterceptKey(int keyCode) {
-            return keyCode == mKeyCode;
-        }
-
-        /**
-         *  True if the rule support long press.
-         */
-        private boolean supportLongPress() {
-            return (mSupportedGestures & KEY_LONGPRESS) != 0;
-        }
-
-        /**
-         *  True if the rule support very long press.
-         */
-        private boolean supportVeryLongPress() {
-            return (mSupportedGestures & KEY_VERYLONGPRESS) != 0;
-        }
-
-        /**
-         *  Maximum count of multi presses.
-         *  Return 1 will trigger onPress immediately when {@link KeyEvent.ACTION_UP}.
-         *  Otherwise trigger onMultiPress immediately when reach max count when
-         *  {@link KeyEvent.ACTION_DOWN}.
-         */
-        int getMaxMultiPressCount() {
-            return 1;
-        }
-
-        /**
-         *  Called when short press has been detected.
-         */
-        abstract void onPress(long downTime);
-        /**
-         *  Callback when multi press (>= 2) has been detected.
-         */
-        void onMultiPress(long downTime, int count) {}
-        /**
-         *  Callback when long press has been detected.
-         */
-        void onLongPress(long downTime) {}
-        /**
-         *  Callback when very long press has been detected.
-         */
-        void onVeryLongPress(long downTime) {}
-
-        @Override
-        public String toString() {
-            return "KeyCode = " + KeyEvent.keyCodeToString(mKeyCode)
-                    + ", long press : " + supportLongPress()
-                    + ", very Long press : " + supportVeryLongPress()
-                    + ", max multi press count : " + getMaxMultiPressCount();
-        }
-    }
-
-    public SingleKeyGestureDetector(Context context) {
-        mLongPressTimeout = ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
-        mVeryLongPressTimeout = context.getResources().getInteger(
-                com.android.internal.R.integer.config_veryLongPressTimeout);
-        mHandler = new KeyHandler();
-    }
-
-    void addRule(SingleKeyRule rule) {
-        mRules.add(rule);
-    }
-
-    void interceptKey(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            interceptKeyDown(event);
-        } else {
-            interceptKeyUp(event);
-        }
-    }
-
-    private void interceptKeyDown(KeyEvent event) {
-        final int keyCode = event.getKeyCode();
-        // same key down.
-        if (mDownKeyCode == keyCode) {
-            if (mActiveRule != null && (event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0
-                    && !mHandledByLongPress) {
-                if (DEBUG) {
-                    Log.i(TAG, "Long press Key " + KeyEvent.keyCodeToString(keyCode));
-                }
-                mHandledByLongPress = true;
-                mHandler.removeMessages(MSG_KEY_LONG_PRESS);
-                mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
-                mActiveRule.onLongPress(event.getEventTime());
-            }
-            return;
-        }
-
-        // When a different key is pressed, stop processing gestures for the currently active key.
-        if (mDownKeyCode != KeyEvent.KEYCODE_UNKNOWN
-                || (mActiveRule != null && !mActiveRule.shouldInterceptKey(keyCode))) {
-            if (DEBUG) {
-                Log.i(TAG, "Press another key " + KeyEvent.keyCodeToString(keyCode));
-            }
-
-            reset();
-        }
-        mDownKeyCode = keyCode;
-
-        // Picks a new rule, return if no rule picked.
-        if (mActiveRule == null) {
-            final int count = mRules.size();
-            for (int index = 0; index < count; index++) {
-                final SingleKeyRule rule = mRules.get(index);
-                if (rule.shouldInterceptKey(keyCode)) {
-                    mActiveRule = rule;
-                    break;
-                }
-            }
-        }
-        if (mActiveRule == null) {
-            return;
-        }
-
-        final long eventTime = event.getEventTime();
-        if (mKeyPressCounter == 0) {
-            if (mActiveRule.supportLongPress()) {
-                final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0,
-                        eventTime);
-                msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, mLongPressTimeout);
-            }
-
-            if (mActiveRule.supportVeryLongPress()) {
-                final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0,
-                        eventTime);
-                msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, mVeryLongPressTimeout);
-            }
-        } else {
-            mHandler.removeMessages(MSG_KEY_LONG_PRESS);
-            mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
-            mHandler.removeMessages(MSG_KEY_DELAYED_PRESS);
-
-            // Trigger multi press immediately when reach max count.( > 1)
-            if (mKeyPressCounter == mActiveRule.getMaxMultiPressCount() - 1) {
-                if (DEBUG) {
-                    Log.i(TAG, "Trigger multi press " + mActiveRule.toString() + " for it"
-                            + " reach the max count " + mKeyPressCounter);
-                }
-                mActiveRule.onMultiPress(eventTime, mKeyPressCounter + 1);
-                mKeyPressCounter = 0;
-            }
-        }
-    }
-
-    private boolean interceptKeyUp(KeyEvent event) {
-        mHandler.removeMessages(MSG_KEY_LONG_PRESS);
-        mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
-        mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
-        if (mActiveRule == null) {
-            return false;
-        }
-
-        if (mHandledByLongPress) {
-            mHandledByLongPress = false;
-            return true;
-        }
-
-        final long downTime = event.getDownTime();
-        if (event.getKeyCode() == mActiveRule.mKeyCode) {
-            // Directly trigger short press when max count is 1.
-            if (mActiveRule.getMaxMultiPressCount() == 1) {
-                mActiveRule.onPress(downTime);
-                return true;
-            }
-
-            // This could be a multi-press.  Wait a little bit longer to confirm.
-            mKeyPressCounter++;
-            Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, mActiveRule.mKeyCode,
-                    mKeyPressCounter, downTime);
-            msg.setAsynchronous(true);
-            mHandler.sendMessageDelayed(msg, MULTI_PRESS_TIMEOUT);
-            return true;
-        }
-        reset();
-        return false;
-    }
-
-    int getKeyPressCounter(int keyCode) {
-        if (mActiveRule != null && mActiveRule.mKeyCode == keyCode) {
-            return mKeyPressCounter;
-        } else {
-            return 0;
-        }
-    }
-
-    void reset() {
-        if (mActiveRule != null) {
-            if (mDownKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
-                mHandler.removeMessages(MSG_KEY_LONG_PRESS);
-                mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
-            }
-
-            if (mKeyPressCounter > 0) {
-                mHandler.removeMessages(MSG_KEY_DELAYED_PRESS);
-                mKeyPressCounter = 0;
-            }
-            mActiveRule = null;
-        }
-
-        mHandledByLongPress = false;
-        mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
-    }
-
-    boolean isKeyIntercepted(int keyCode) {
-        if (mActiveRule != null && mActiveRule.shouldInterceptKey(keyCode)) {
-            return mHandledByLongPress;
-        }
-        return false;
-    }
-
-    private class KeyHandler extends Handler {
-        KeyHandler() {
-            super(Looper.getMainLooper());
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (mActiveRule == null) {
-                return;
-            }
-            final int keyCode = msg.arg1;
-            final long eventTime = (long) msg.obj;
-            switch(msg.what) {
-                case MSG_KEY_LONG_PRESS:
-                    if (DEBUG) {
-                        Log.i(TAG, "Detect long press " + KeyEvent.keyCodeToString(keyCode));
-                    }
-                    mHandledByLongPress = true;
-                    mActiveRule.onLongPress(eventTime);
-                    break;
-                case MSG_KEY_VERY_LONG_PRESS:
-                    if (DEBUG) {
-                        Log.i(TAG, "Detect very long press "
-                                + KeyEvent.keyCodeToString(keyCode));
-                    }
-                    mHandledByLongPress = true;
-                    mActiveRule.onVeryLongPress(eventTime);
-                    break;
-                case MSG_KEY_DELAYED_PRESS:
-                    if (DEBUG) {
-                        Log.i(TAG, "Detect press " + KeyEvent.keyCodeToString(keyCode)
-                                + ", count " + mKeyPressCounter);
-                    }
-                    if (mKeyPressCounter == 1) {
-                        mActiveRule.onPress(eventTime);
-                    } else {
-                        mActiveRule.onMultiPress(eventTime, mKeyPressCounter);
-                    }
-                    mKeyPressCounter = 0;
-                    break;
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/role/OWNERS b/services/core/java/com/android/server/role/OWNERS
index 31e3549..dafdf0f 100644
--- a/services/core/java/com/android/server/role/OWNERS
+++ b/services/core/java/com/android/server/role/OWNERS
@@ -1,5 +1 @@
-svetoslavganov@google.com
-zhanghai@google.com
-evanseverson@google.com
-eugenesusla@google.com
-ntmyren@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/services/core/java/com/android/server/security/KeyChainSystemService.java b/services/core/java/com/android/server/security/KeyChainSystemService.java
index 3c06d0e..edd4a3d 100644
--- a/services/core/java/com/android/server/security/KeyChainSystemService.java
+++ b/services/core/java/com/android/server/security/KeyChainSystemService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.security;
 
+import static android.os.PowerWhitelistManager.REASON_KEY_CHAIN;
+
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -102,7 +104,8 @@
         final DeviceIdleInternal idleController =
                 LocalServices.getService(DeviceIdleInternal.class);
         idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
-                KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain");
+                KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false,
+                REASON_KEY_CHAIN, "keychain");
 
         getContext().startServiceAsUser(intent, user);
     }
diff --git a/services/core/java/com/android/server/servicewatcher/OWNERS b/services/core/java/com/android/server/servicewatcher/OWNERS
new file mode 100644
index 0000000..ced619f
--- /dev/null
+++ b/services/core/java/com/android/server/servicewatcher/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 25692
+
+sooniln@google.com
+wyattriley@google.com
+
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
similarity index 99%
rename from services/core/java/com/android/server/ServiceWatcher.java
rename to services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
index 8a2894c..5d49663 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.servicewatcher;
 
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_NOT_FOREGROUND;
@@ -52,6 +52,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index de8823c..6366280 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -39,6 +39,7 @@
 import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundModelType;
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
+import android.os.HidlMemory;
 import android.os.HidlMemoryUtil;
 import android.os.ParcelFileDescriptor;
 
@@ -199,18 +200,7 @@
         hidlModel.header.type = aidl2hidlSoundModelType(aidlModel.type);
         hidlModel.header.uuid = aidl2hidlUuid(aidlModel.uuid);
         hidlModel.header.vendorUuid = aidl2hidlUuid(aidlModel.vendorUuid);
-
-        // Extract a dup of the underlying FileDescriptor out of aidlModel.data without changing
-        // the original.
-        FileDescriptor fd = new FileDescriptor();
-        try {
-            ParcelFileDescriptor dup = aidlModel.data.dup();
-            fd.setInt$(dup.detachFd());
-            hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(fd, aidlModel.dataSize);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-
+        hidlModel.data = parcelFileDescriptorToHidlMemory(aidlModel.data, aidlModel.dataSize);
         return hidlModel;
     }
 
@@ -425,4 +415,31 @@
         }
         return aidlCapabilities;
     }
+
+    /**
+     * Convert an AIDL representation of a shared memory block (ParcelFileDescriptor + size) to the
+     * HIDL representation (HidlMemory). Will not change the incoming data or any ownership
+     * semantics, but rather duplicate the underlying FD.
+     *
+     * @param data     The incoming memory block. May be null if dataSize is 0.
+     * @param dataSize The number of bytes in the block.
+     * @return A HidlMemory representation of the memory block. Will be non-null even for an empty
+     *         block.
+     */
+    private static @NonNull
+    HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) {
+        if (dataSize > 0) {
+            // Extract a dup of the underlying FileDescriptor out of data.
+            FileDescriptor fd = new FileDescriptor();
+            try {
+                ParcelFileDescriptor dup = data.dup();
+                fd.setInt$(dup.detachFd());
+                return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } else {
+            return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index ebe9733..212f81f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
@@ -35,8 +35,7 @@
  * HAL whenever they expire.
  */
 public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
-    // TODO(b/166328980): Reduce this to 1000 as soon as HAL is fixed.
-    private static final long TIMEOUT_MS = 10000;
+    private static final long TIMEOUT_MS = 3000;
     private static final String TAG = "SoundTriggerHw2Watchdog";
 
     private final @NonNull
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
index 43047d1..e05c468 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
@@ -62,7 +62,9 @@
         }
         validateUuid(model.uuid);
         validateUuid(model.vendorUuid);
-        Objects.requireNonNull(model.data);
+        if (model.dataSize > 0) {
+            Objects.requireNonNull(model.data);
+        }
     }
 
     static void validatePhraseModel(@Nullable PhraseSoundModel model) {
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 6aa7c8a..7ed7a59 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -3759,13 +3759,15 @@
             ConnectivityManager.NetworkCallback {
         @Override
         public void onAvailable(Network network) {
-            FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, network.netId,
+            FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED,
+                    network.getNetId(),
                     FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED__STATE__CONNECTED);
         }
 
         @Override
         public void onLost(Network network) {
-            FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, network.netId,
+            FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED,
+                    network.getNetId(),
                     FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED__STATE__DISCONNECTED);
         }
     }
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 917d05c..dedb3ac 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -163,22 +163,17 @@
      *
      * @return ANR dialog delay in milliseconds
      */
-    public long getAnrDelayMillis(String packageName, int uid)
+    public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
             throws ExternalStorageServiceException {
+        final int userId = UserHandle.getUserId(uid);
+        final StorageUserConnection connection;
         synchronized (mLock) {
-            int size = mConnections.size();
-            for (int i = 0; i < size; i++) {
-                int key = mConnections.keyAt(i);
-                StorageUserConnection connection = mConnections.get(key);
-                if (connection != null) {
-                    long delay = connection.getAnrDelayMillis(packageName, uid);
-                    if (delay > 0) {
-                        return delay;
-                    }
-                }
-            }
+            connection = mConnections.get(userId);
         }
-        return 0;
+
+        if (connection != null) {
+            connection.notifyAnrDelayStarted(packageName, uid, tid, reason);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 9880d32..9409eb5 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -16,7 +16,6 @@
 
 package com.android.server.storage;
 
-import static android.service.storage.ExternalStorageService.EXTRA_ANR_TIMEOUT_MS;
 import static android.service.storage.ExternalStorageService.EXTRA_ERROR;
 import static android.service.storage.ExternalStorageService.FLAG_SESSION_ATTRIBUTE_INDEXABLE;
 import static android.service.storage.ExternalStorageService.FLAG_SESSION_TYPE_FUSE;
@@ -54,11 +53,13 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 /**
  * Controls the lifecycle of the {@link ActiveConnection} to an {@link ExternalStorageService}
@@ -73,6 +74,7 @@
     private final Context mContext;
     private final int mUserId;
     private final StorageSessionController mSessionController;
+    private final StorageManagerInternal mSmInternal;
     private final ActiveConnection mActiveConnection = new ActiveConnection();
     @GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
     @GuardedBy("mLock") private final Set<Integer> mUidsBlockedOnIo = new ArraySet<>();
@@ -82,6 +84,7 @@
         mContext = Objects.requireNonNull(context);
         mUserId = Preconditions.checkArgumentNonnegative(userId);
         mSessionController = controller;
+        mSmInternal = LocalServices.getService(StorageManagerInternal.class);
         mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
         mHandlerThread.start();
     }
@@ -151,17 +154,17 @@
      *
      * @return ANR dialog delay in milliseconds
      */
-    public long getAnrDelayMillis(String packageName, int uid)
+    public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
             throws ExternalStorageServiceException {
+        List<String> primarySessionIds = mSmInternal.getPrimaryVolumeIds();
         synchronized (mSessionsLock) {
             for (String sessionId : mSessions.keySet()) {
-                long delay = mActiveConnection.getAnrDelayMillis(packageName, uid);
-                if (delay > 0) {
-                    return delay;
+                if (primarySessionIds.contains(sessionId)) {
+                    mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
+                    return;
                 }
             }
         }
-        return 0;
     }
 
     /**
@@ -206,8 +209,7 @@
                 return;
             }
         }
-        StorageManagerInternal sm = LocalServices.getService(StorageManagerInternal.class);
-        sm.resetUser(mUserId);
+        mSmInternal.resetUser(mUserId);
     }
 
     /**
@@ -292,9 +294,6 @@
         @GuardedBy("mLock")
         private final ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
 
-        @GuardedBy("mLock")
-        private final ArrayList<CompletableFuture<Long>> mOutstandingTimeoutOps = new ArrayList<>();
-
         @Override
         public void close() {
             ServiceConnection oldConnection = null;
@@ -311,9 +310,6 @@
                 for (CompletableFuture<Void> op : mOutstandingOps) {
                     op.cancel(true);
                 }
-                for (CompletableFuture<Long> op : mOutstandingTimeoutOps) {
-                    op.cancel(true);
-                }
                 mOutstandingOps.clear();
             }
 
@@ -328,6 +324,23 @@
             }
         }
 
+        private void asyncBestEffort(Consumer<IExternalStorageService> consumer) {
+            synchronized (mLock) {
+                if (mRemoteFuture == null) {
+                    Slog.w(TAG, "Dropping async request service is not bound");
+                    return;
+                }
+
+                IExternalStorageService service = mRemoteFuture.getNow(null);
+                if (service == null) {
+                    Slog.w(TAG, "Dropping async request service is not connected");
+                    return;
+                }
+
+                consumer.accept(service);
+            }
+        }
+
         private void waitForAsyncVoid(AsyncStorageServiceCall asyncCall) throws Exception {
             CompletableFuture<Void> opFuture = new CompletableFuture<>();
             RemoteCallback callback = new RemoteCallback(result -> setResult(result, opFuture));
@@ -336,15 +349,6 @@
                     DEFAULT_REMOTE_TIMEOUT_SECONDS);
         }
 
-        private long waitForAsyncLong(AsyncStorageServiceCall asyncCall) throws Exception {
-            CompletableFuture<Long> opFuture = new CompletableFuture<>();
-            RemoteCallback callback =
-                    new RemoteCallback(result -> setTimeoutResult(result, opFuture));
-
-            return waitForAsync(asyncCall, callback, opFuture, mOutstandingTimeoutOps,
-                    1 /* timeoutSeconds */);
-        }
-
         private <T> T waitForAsync(AsyncStorageServiceCall asyncCall, RemoteCallback callback,
                 CompletableFuture<T> opFuture, ArrayList<CompletableFuture<T>> outstandingOps,
                 long timeoutSeconds) throws Exception {
@@ -419,25 +423,15 @@
             }
         }
 
-        public long getAnrDelayMillis(String packgeName, int uid)
+        public void notifyAnrDelayStarted(String packgeName, int uid, int tid, int reason)
                 throws ExternalStorageServiceException {
-            try {
-                return waitForAsyncLong((service, callback) ->
-                        service.getAnrDelayMillis(packgeName, uid, callback));
-            } catch (Exception e) {
-                throw new ExternalStorageServiceException("Failed to notify app not responding: "
-                        + packgeName, e);
-            }
-        }
-
-        private void setTimeoutResult(Bundle result, CompletableFuture<Long> future) {
-            ParcelableException ex = result.getParcelable(EXTRA_ERROR);
-            if (ex != null) {
-                future.completeExceptionally(ex);
-            } else {
-                long timeoutMs = result.getLong(EXTRA_ANR_TIMEOUT_MS);
-                future.complete(timeoutMs);
-            }
+            asyncBestEffort(service -> {
+                try {
+                    service.notifyAnrDelayStarted(packgeName, uid, tid, reason);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to notify ANR delay started", e);
+                }
+            });
         }
 
         private void setResult(Bundle result, CompletableFuture<Void> future) {
diff --git a/services/core/java/com/android/server/telecom/InternalServiceRepository.java b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
index 76ea5c7..bd1746d 100644
--- a/services/core/java/com/android/server/telecom/InternalServiceRepository.java
+++ b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom;
 
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+
 import android.content.Context;
 import android.os.Binder;
 import android.os.Process;
@@ -38,7 +40,7 @@
         public void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
                 String reason) {
             mDeviceIdleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
-                    duration, userHandle, true /*sync*/, reason);
+                    duration, userHandle, true /*sync*/, REASON_UNKNOWN, reason);
         }
     };
 
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
index 531c62c..0b51488 100644
--- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
@@ -39,8 +39,8 @@
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.ServiceWatcher;
-import com.android.server.ServiceWatcher.BoundService;
+import com.android.server.servicewatcher.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher.BoundService;
 
 import java.util.Objects;
 import java.util.function.Predicate;
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index b6ddd93..b2db9f5 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -65,7 +65,7 @@
     @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();
 
     @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
-    private boolean mIsRunning = true;
+    private boolean mIsQuitting = false;
 
     @Nullable private UnderlyingNetworkRecord mCurrentRecord;
     @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
@@ -151,7 +151,7 @@
         mVcnContext.ensureRunningOnLooperThread();
 
         // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
-        if (!mIsRunning) {
+        if (mIsQuitting) {
             return;
         }
 
@@ -205,7 +205,7 @@
         }
         mCellBringupCallbacks.clear();
 
-        mIsRunning = false;
+        mIsQuitting = true;
     }
 
     /** Returns whether the currently selected Network matches the given network. */
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 6ad30b5..9d39c67 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,6 +16,8 @@
 
 package com.android.server.vcn;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+
 import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
@@ -84,6 +86,13 @@
      */
     private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2;
 
+    /**
+     * A GatewayConnection owned by this VCN quit.
+     *
+     * @param obj VcnGatewayConnectionConfig
+     */
+    private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
+
     /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
     private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
 
@@ -208,6 +217,9 @@
             case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
                 handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
                 break;
+            case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
+                handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
+                break;
             case MSG_CMD_TEARDOWN:
                 handleTeardown();
                 break;
@@ -263,7 +275,7 @@
 
         // If preexisting VcnGatewayConnection(s) satisfy request, return
         for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
-            if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
+            if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                 if (VDBG) {
                     Slog.v(
                             getLogTag(),
@@ -278,7 +290,7 @@
         // up
         for (VcnGatewayConnectionConfig gatewayConnectionConfig :
                 mConfig.getGatewayConnectionConfigs()) {
-            if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
+            if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                 Slog.v(
                         getLogTag(),
                         "Bringing up new VcnGatewayConnection for request " + request.requestId);
@@ -289,12 +301,21 @@
                                 mSubscriptionGroup,
                                 mLastSnapshot,
                                 gatewayConnectionConfig,
-                                new VcnGatewayStatusCallbackImpl());
+                                new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
                 mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
             }
         }
     }
 
+    private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
+        Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
+        mVcnGatewayConnections.remove(config);
+
+        // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
+        // start a new GatewayConnection)
+        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+    }
+
     private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
         mLastSnapshot = snapshot;
 
@@ -305,9 +326,10 @@
         }
     }
 
-    private boolean requestSatisfiedByGatewayConnectionConfig(
+    private boolean isRequestSatisfiedByGatewayConnectionConfig(
             @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+        builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         for (int cap : config.getAllExposedCapabilities()) {
             builder.addCapability(cap);
         }
@@ -339,9 +361,23 @@
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage);
+
+        /** Called by a VcnGatewayConnection to indicate that it has fully torn down. */
+        void onQuit();
     }
 
     private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
+        public final VcnGatewayConnectionConfig mGatewayConnectionConfig;
+
+        VcnGatewayStatusCallbackImpl(VcnGatewayConnectionConfig gatewayConnectionConfig) {
+            mGatewayConnectionConfig = gatewayConnectionConfig;
+        }
+
+        @Override
+        public void onQuit() {
+            sendMessage(obtainMessage(MSG_EVENT_GATEWAY_CONNECTION_QUIT, mGatewayConnectionConfig));
+        }
+
         @Override
         public void onEnteredSafeMode() {
             sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 06748a3..6bc9978 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -168,6 +168,8 @@
     private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: ";
     private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
             "Underlying Network lost";
+    private static final String DISCONNECT_REASON_NETWORK_AGENT_UNWANTED =
+            "NetworkAgent was unwanted";
     private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
     private static final int TOKEN_ALL = Integer.MIN_VALUE;
 
@@ -379,13 +381,16 @@
         /** The reason why the disconnect was requested. */
         @NonNull public final String reason;
 
-        EventDisconnectRequestedInfo(@NonNull String reason) {
+        public final boolean shouldQuit;
+
+        EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldQuit) {
             this.reason = Objects.requireNonNull(reason);
+            this.shouldQuit = shouldQuit;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(reason);
+            return Objects.hash(reason, shouldQuit);
         }
 
         @Override
@@ -395,7 +400,7 @@
             }
 
             final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other;
-            return reason.equals(rhs.reason);
+            return reason.equals(rhs.reason) && shouldQuit == rhs.shouldQuit;
         }
     }
 
@@ -488,8 +493,14 @@
      */
     @NonNull private final VcnWakeLock mWakeLock;
 
-    /** Running state of this VcnGatewayConnection. */
-    private boolean mIsRunning = true;
+    /**
+     * Whether the VcnGatewayConnection is in the process of irreversibly quitting.
+     *
+     * <p>This variable is false for the lifecycle of the VcnGatewayConnection, until a command to
+     * teardown has been received. This may be flipped due to events such as the Network becoming
+     * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure.
+     */
+    private boolean mIsQuitting = false;
 
     /**
      * The token used by the primary/current/active session.
@@ -622,10 +633,8 @@
      * <p>Once torn down, this VcnTunnel CANNOT be started again.
      */
     public void teardownAsynchronously() {
-        sendMessageAndAcquireWakeLock(
-                EVENT_DISCONNECT_REQUESTED,
-                TOKEN_ALL,
-                new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
+        sendDisconnectRequestedAndAcquireWakelock(
+                DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */);
 
         // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
         // is also called asynchronously when a NetworkAgent becomes unwanted
@@ -646,6 +655,8 @@
         cancelSafeModeAlarm();
 
         mUnderlyingNetworkTracker.teardown();
+
+        mGatewayStatusCallback.onQuit();
     }
 
     /**
@@ -693,7 +704,7 @@
     private void acquireWakeLock() {
         mVcnContext.ensureRunningOnLooperThread();
 
-        if (mIsRunning) {
+        if (!mIsQuitting) {
             mWakeLock.acquire();
         }
     }
@@ -892,7 +903,7 @@
                         TOKEN_ALL,
                         0 /* arg2 */,
                         new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
         mDisconnectRequestAlarm =
                 createScheduledAlarm(
                         DISCONNECT_REQUEST_ALARM,
@@ -909,7 +920,8 @@
         // Cancel any existing disconnect due to previous loss of underlying network
         removeEqualMessages(
                 EVENT_DISCONNECT_REQUESTED,
-                new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+                new EventDisconnectRequestedInfo(
+                        DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
     }
 
     private void setRetryTimeoutAlarm(long delay) {
@@ -1041,11 +1053,8 @@
                 enterState();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessageAndAcquireWakeLock(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+                sendDisconnectRequestedAndAcquireWakelock(
+                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
         }
 
@@ -1083,11 +1092,8 @@
                 processStateMsg(msg);
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessageAndAcquireWakeLock(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+                sendDisconnectRequestedAndAcquireWakelock(
+                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
 
             // Attempt to release the WakeLock - only possible if the Handler queue is empty
@@ -1104,11 +1110,8 @@
                 exitState();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessageAndAcquireWakeLock(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+                sendDisconnectRequestedAndAcquireWakelock(
+                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
         }
 
@@ -1141,11 +1144,11 @@
             }
         }
 
-        protected void handleDisconnectRequested(String msg) {
+        protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) {
             // TODO(b/180526152): notify VcnStatusCallback for Network loss
 
-            Slog.v(TAG, "Tearing down. Cause: " + msg);
-            mIsRunning = false;
+            Slog.v(TAG, "Tearing down. Cause: " + info.reason);
+            mIsQuitting = info.shouldQuit;
 
             teardownNetwork();
 
@@ -1177,7 +1180,7 @@
     private class DisconnectedState extends BaseState {
         @Override
         protected void enterState() {
-            if (!mIsRunning) {
+            if (mIsQuitting) {
                 quitNow(); // Ignore all queued events; cleanup is complete.
             }
 
@@ -1200,9 +1203,11 @@
                     }
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    mIsRunning = false;
+                    if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) {
+                        mIsQuitting = true;
 
-                    quitNow();
+                        quitNow();
+                    }
                     break;
                 default:
                     logUnhandledMessage(msg);
@@ -1284,10 +1289,11 @@
 
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
+                    EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj);
+                    mIsQuitting = info.shouldQuit;
                     teardownNetwork();
 
-                    String reason = ((EventDisconnectRequestedInfo) msg.obj).reason;
-                    if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
+                    if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
                         // TODO(b/180526152): notify VcnStatusCallback for Network loss
 
                         // Will trigger EVENT_SESSION_CLOSED immediately.
@@ -1300,7 +1306,7 @@
                 case EVENT_SESSION_CLOSED:
                     mIkeSession = null;
 
-                    if (mIsRunning && mUnderlying != null) {
+                    if (!mIsQuitting && mUnderlying != null) {
                         transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
                     } else {
                         teardownNetwork();
@@ -1391,7 +1397,7 @@
                     transitionTo(mConnectedState);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                     mGatewayStatusCallback.onEnteredSafeMode();
@@ -1438,6 +1444,7 @@
                             mVcnContext.getVcnNetworkProvider()) {
                         @Override
                         public void unwanted() {
+                            Slog.d(TAG, "NetworkAgent was unwanted");
                             teardownAsynchronously();
                         }
 
@@ -1471,7 +1478,7 @@
                 @NonNull IpSecTransform transform,
                 int direction) {
             try {
-                // TODO(b/180163196): Set underlying network of tunnel interface
+                tunnelIface.setUnderlyingNetwork(underlyingNetwork);
 
                 // Transforms do not need to be persisted; the IkeSession will keep them alive
                 mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
@@ -1577,7 +1584,7 @@
                     setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                     mGatewayStatusCallback.onEnteredSafeMode();
@@ -1682,7 +1689,7 @@
                     transitionTo(mConnectingState);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                     mGatewayStatusCallback.onEnteredSafeMode();
@@ -1905,13 +1912,13 @@
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    boolean isRunning() {
-        return mIsRunning;
+    boolean isQuitting() {
+        return mIsQuitting;
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    void setIsRunning(boolean isRunning) {
-        mIsRunning = isRunning;
+    void setIsQuitting(boolean isQuitting) {
+        mIsQuitting = isQuitting;
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1924,6 +1931,14 @@
         mIkeSession = session;
     }
 
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
+        sendMessageAndAcquireWakeLock(
+                EVENT_DISCONNECT_REQUESTED,
+                TOKEN_ALL,
+                new EventDisconnectRequestedInfo(reason, shouldQuit));
+    }
+
     private IkeSessionParams buildIkeParams() {
         // TODO: Implement this once IkeSessionParams is persisted
         return null;
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index bfeec01..a909695 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -67,9 +67,7 @@
         mListeners.add(listener);
 
         // Send listener all cached requests
-        for (NetworkRequestEntry entry : mRequests.values()) {
-            notifyListenerForEvent(listener, entry);
-        }
+        resendAllRequests(listener);
     }
 
     /** Unregisters the specified listener from receiving future NetworkRequests. */
@@ -78,6 +76,14 @@
         mListeners.remove(listener);
     }
 
+    /** Sends all cached NetworkRequest(s) to the specified listener. */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public void resendAllRequests(@NonNull NetworkRequestListener listener) {
+        for (NetworkRequestEntry entry : mRequests.values()) {
+            notifyListenerForEvent(listener, entry);
+        }
+    }
+
     private void notifyListenerForEvent(
             @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
         listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
index 685dce4..96f84dc 100644
--- a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
+++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
@@ -16,6 +16,7 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.input.InputManager;
 import android.os.CombinedVibrationEffect;
@@ -33,7 +34,11 @@
 
     private final Object mLock = new Object();
     private final Handler mHandler;
-    private final InputManager mInputManager;
+    private final Context mContext;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private InputManager mInputManager;
 
     @GuardedBy("mLock")
     private final SparseArray<VibratorManager> mInputDeviceVibrators = new SparseArray<>();
@@ -47,7 +52,13 @@
 
     InputDeviceDelegate(Context context, Handler handler) {
         mHandler = handler;
-        mInputManager = context.getSystemService(InputManager.class);
+        mContext = context;
+    }
+
+    public void onSystemReady() {
+        synchronized (mLock) {
+            mInputManager = mContext.getSystemService(InputManager.class);
+        }
     }
 
     @Override
@@ -116,6 +127,10 @@
      */
     public boolean updateInputDeviceVibrators(boolean vibrateInputDevices) {
         synchronized (mLock) {
+            if (mInputManager == null) {
+                // Ignore update, service not loaded yet so change cannot be applied.
+                return false;
+            }
             if (vibrateInputDevices == mShouldVibrateInputDevices) {
                 // No need to update if settings haven't changed.
                 return false;
@@ -150,6 +165,10 @@
 
     private void updateInputDevice(int deviceId) {
         synchronized (mLock) {
+            if (mInputManager == null) {
+                // Ignore update, service not loaded yet so change cannot be applied.
+                return;
+            }
             if (!mShouldVibrateInputDevices) {
                 // No need to keep this device vibrator if setting is off.
                 return;
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index 607da3c..e84ee672 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -120,7 +120,9 @@
         if (newEffect.equals(mEffect)) {
             return;
         }
-        mOriginalEffect = mEffect;
+        if (mOriginalEffect == null) {
+            mOriginalEffect = mEffect;
+        }
         mEffect = newEffect;
     }
 
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 334129d..4a07c1a 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -16,6 +16,7 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.IUidObserver;
 import android.content.Context;
@@ -57,8 +58,6 @@
 
     private final Object mLock = new Object();
     private final Context mContext;
-    private final Vibrator mVibrator;
-    private final AudioManager mAudioManager;
     private final SettingsObserver mSettingObserver;
     @VisibleForTesting
     final UidObserver mUidObserver;
@@ -68,6 +67,13 @@
     private final SparseArray<VibrationEffect> mFallbackEffects;
 
     @GuardedBy("mLock")
+    @Nullable
+    private Vibrator mVibrator;
+    @GuardedBy("mLock")
+    @Nullable
+    private AudioManager mAudioManager;
+
+    @GuardedBy("mLock")
     private boolean mVibrateInputDevices;
     @GuardedBy("mLock")
     private boolean mVibrateWhenRinging;
@@ -86,22 +92,9 @@
 
     VibrationSettings(Context context, Handler handler) {
         mContext = context;
-        mVibrator = context.getSystemService(Vibrator.class);
-        mAudioManager = context.getSystemService(AudioManager.class);
         mSettingObserver = new SettingsObserver(handler);
         mUidObserver = new UidObserver();
 
-        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
-        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
-        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
-        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
-        registerSettingsObserver(
-                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
-        registerSettingsObserver(
-                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY));
-        registerSettingsObserver(
-                Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
-
         VibrationEffect clickEffect = createEffectFromResource(
                 com.android.internal.R.array.config_virtualKeyVibePattern);
         VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
@@ -119,6 +112,15 @@
         mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
                 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
 
+        // Update with current values from settings.
+        updateSettings();
+    }
+
+    public void onSystemReady() {
+        synchronized (mLock) {
+            mVibrator = mContext.getSystemService(Vibrator.class);
+            mAudioManager = mContext.getSystemService(AudioManager.class);
+        }
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
@@ -148,7 +150,18 @@
                     }
                 });
 
-        // Update with current values from settings.
+        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
+        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
+        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
+        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
+
+        // Update with newly loaded services.
         updateSettings();
     }
 
@@ -178,17 +191,21 @@
      * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
      */
     public int getDefaultIntensity(int usageHint) {
-        if (isRingtone(usageHint)) {
-            return mVibrator.getDefaultRingVibrationIntensity();
-        } else if (isNotification(usageHint)) {
-            return mVibrator.getDefaultNotificationVibrationIntensity();
-        } else if (isHapticFeedback(usageHint)) {
-            return mVibrator.getDefaultHapticFeedbackIntensity();
-        } else if (isAlarm(usageHint)) {
+        if (isAlarm(usageHint)) {
             return Vibrator.VIBRATION_INTENSITY_HIGH;
-        } else {
-            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
         }
+        synchronized (mLock) {
+            if (mVibrator != null) {
+                if (isRingtone(usageHint)) {
+                    return mVibrator.getDefaultRingVibrationIntensity();
+                } else if (isNotification(usageHint)) {
+                    return mVibrator.getDefaultNotificationVibrationIntensity();
+                } else if (isHapticFeedback(usageHint)) {
+                    return mVibrator.getDefaultHapticFeedbackIntensity();
+                }
+            }
+        }
+        return Vibrator.VIBRATION_INTENSITY_MEDIUM;
     }
 
     /**
@@ -234,8 +251,11 @@
         if (!isRingtone(usageHint)) {
             return true;
         }
-        int ringerMode = mAudioManager.getRingerModeInternal();
         synchronized (mLock) {
+            if (mAudioManager == null) {
+                return false;
+            }
+            int ringerMode = mAudioManager.getRingerModeInternal();
             if (mVibrateWhenRinging) {
                 return ringerMode != AudioManager.RINGER_MODE_SILENT;
             } else if (mApplyRampingRinger) {
@@ -304,12 +324,12 @@
             mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
             mApplyRampingRinger = getGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0) != 0;
             mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                    mVibrator.getDefaultHapticFeedbackIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
             mNotificationIntensity = getSystemSetting(
                     Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                    mVibrator.getDefaultNotificationVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
             mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                    mVibrator.getDefaultRingVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
             mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
             mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
         }
@@ -346,15 +366,15 @@
             proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
                     mHapticFeedbackIntensity);
             proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultHapticFeedbackIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
             proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_INTENSITY,
                     mNotificationIntensity);
             proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultNotificationVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
             proto.write(VibratorManagerServiceDumpProto.RING_INTENSITY,
                     mRingIntensity);
             proto.write(VibratorManagerServiceDumpProto.RING_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultRingVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
         }
     }
 
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 1750854..c9751bb 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -127,9 +127,9 @@
     @GuardedBy("mLock")
     private ExternalVibrationHolder mCurrentExternalVibration;
 
-    private VibrationSettings mVibrationSettings;
-    private VibrationScaler mVibrationScaler;
-    private InputDeviceDelegate mInputDeviceDelegate;
+    private final VibrationSettings mVibrationSettings;
+    private final VibrationScaler mVibrationScaler;
+    private final InputDeviceDelegate mInputDeviceDelegate;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -170,6 +170,10 @@
         mContext = context;
         mHandler = injector.createHandler(Looper.myLooper());
 
+        mVibrationSettings = new VibrationSettings(mContext, mHandler);
+        mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
+        mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
+
         VibrationCompleteListener listener = new VibrationCompleteListener(this);
         mNativeWrapper = injector.getNativeWrapper();
         mNativeWrapper.init(listener);
@@ -224,12 +228,12 @@
         Slog.v(TAG, "Initializing VibratorManager service...");
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "systemReady");
         try {
-            mVibrationSettings = new VibrationSettings(mContext, mHandler);
-            mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
-            mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
+            mVibrationSettings.onSystemReady();
+            mInputDeviceDelegate.onSystemReady();
 
             mVibrationSettings.addListener(this::updateServiceState);
 
+            // Will update settings and input devices.
             updateServiceState();
         } finally {
             Slog.v(TAG, "VibratorManager service initialized");
@@ -340,10 +344,11 @@
             if (!isEffectValid(effect)) {
                 return;
             }
-            effect = fixupVibrationEffect(effect);
             attrs = fixupVibrationAttributes(attrs);
             Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
                     uid, opPkg, reason);
+            // Update with fixed up effect to keep the original effect in Vibration for debugging.
+            vib.updateEffect(fixupVibrationEffect(effect));
 
             synchronized (mLock) {
                 Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib);
@@ -1134,6 +1139,9 @@
         void dumpText(PrintWriter pw) {
             pw.println("Vibrator Manager Service:");
             synchronized (mLock) {
+                pw.println("  mVibrationSettings:");
+                pw.println("    " + mVibrationSettings);
+                pw.println();
                 pw.println("  mVibratorControllers:");
                 for (int i = 0; i < mVibrators.size(); i++) {
                     pw.println("    " + mVibrators.valueAt(i));
@@ -1142,14 +1150,15 @@
                 pw.println("  mCurrentVibration:");
                 pw.println("    " + (mCurrentVibration == null
                         ? null : mCurrentVibration.getVibration().getDebugInfo()));
+                pw.println();
                 pw.println("  mNextVibration:");
                 pw.println("    " + (mNextVibration == null
                         ? null : mNextVibration.getVibration().getDebugInfo()));
+                pw.println();
                 pw.println("  mCurrentExternalVibration:");
                 pw.println("    " + (mCurrentExternalVibration == null
                         ? null : mCurrentExternalVibration.getDebugInfo()));
                 pw.println();
-                pw.println("  mVibrationSettings=" + mVibrationSettings);
                 for (int i = 0; i < mPreviousVibrations.size(); i++) {
                     pw.println();
                     pw.print("  Previous vibrations for usage ");
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 3bbc81a..e6d37b6 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1861,7 +1861,7 @@
         }
 
         @Override
-        public boolean isEnabled() {
+        public boolean isAccessibilityTracingEnabled() {
             return mTracing.isEnabled();
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 151895f..c830ba9 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -808,7 +808,7 @@
 
                 if (rootTask.inFreeformWindowingMode()) {
                     rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-                } else if (!mService.mSizeCompatFreeform && r.inSizeCompatMode()) {
+                } else if (!mService.mSupportsNonResizableMultiWindow && r.inSizeCompatMode()) {
                     throw new IllegalStateException("Size-compat windows are currently not"
                             + "freeform-enabled");
                 } else if (rootTask.getParent().inFreeformWindowingMode()) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f40f4a9..77c369f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -132,7 +132,6 @@
 import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
 import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
 import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
-import static com.android.server.wm.ActivityRecordProto.FROZEN_BOUNDS;
 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
 import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
@@ -215,6 +214,7 @@
 import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.letterboxBackgroundTypeToString;
 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
@@ -344,7 +344,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -582,9 +581,6 @@
 
     private Task mLastParent;
 
-    // Have we told the window clients to show themselves?
-    private boolean mClientVisible;
-
     boolean firstWindowDrawn;
     /** Whether the visible window(s) of this activity is drawn. */
     private boolean mReportedDrawn;
@@ -732,9 +728,6 @@
     // windows, where the app hasn't had time to set a value on the window.
     int mRotationAnimationHint = -1;
 
-    ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
-    ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
-
     private AppSaturationInfo mLastAppSaturationInfo;
 
     private final ColorDisplayService.ColorTransformController mColorTransformController =
@@ -763,6 +756,10 @@
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
 
+    // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be used
+    // without security checks
+    final Binder shareableActivityToken = new Binder();
+
     // Tracking cookie for the launch of this activity and it's task.
     IBinder mLaunchCookie;
 
@@ -911,7 +908,7 @@
                         pw.print(Integer.toHexString(taskDescription.getStatusBarColor()));
                         pw.print(" navigationBarColor=");
                         pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
-                        pw.print(" backgroundColorFloating=");
+                        pw.print(prefix); pw.print(" backgroundColorFloating=");
                         pw.println(Integer.toHexString(
                                 taskDescription.getBackgroundColorFloating()));
             }
@@ -999,7 +996,7 @@
         pw.print(prefix); pw.print("mOrientation=");
         pw.println(ActivityInfo.screenOrientationToString(mOrientation));
         pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
-                + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible
+                + " mVisible=" + mVisible + " mClientVisible=" + isClientVisible()
                 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
                 + " reportedDrawn=" + mReportedDrawn + " reportedVisible=" + reportedVisible);
         if (paused) {
@@ -1031,10 +1028,6 @@
             pw.println(" mVisibleSetFromTransferredStartingWindow="
                     + mVisibleSetFromTransferredStartingWindow);
         }
-        if (!mFrozenBounds.isEmpty()) {
-            pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
-            pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
-        }
         if (mPendingRelaunchCount != 0) {
             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
         }
@@ -1085,6 +1078,46 @@
                 pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
             }
         }
+
+        dumpLetterboxInfo(pw, prefix);
+    }
+
+    private void dumpLetterboxInfo(PrintWriter pw, String prefix) {
+        final WindowState mainWin = findMainWindow();
+        if (mainWin == null) {
+            return;
+        }
+
+        boolean isLetterboxed = isLetterboxed(mainWin);
+        pw.println(prefix + "isLetterboxed=" + isLetterboxed);
+        if (!isLetterboxed) {
+            return;
+        }
+
+        pw.println(prefix + "  letterboxReason=" + getLetterboxReasonString(mainWin));
+        pw.println(prefix + "  letterboxBackgroundColor=" + Integer.toHexString(
+                getLetterboxBackgroundColor().toArgb()));
+        pw.println(prefix + "  letterboxBackgroundType="
+                + letterboxBackgroundTypeToString(mWmService.getLetterboxBackgroundType()));
+        pw.println(prefix + "  letterboxAspectRatio="
+                + computeAspectRatio(getBounds()));
+    }
+
+    /**
+     * Returns a string representing the reason for letterboxing. This method assumes the activity
+     * is letterboxed.
+     */
+    private String getLetterboxReasonString(WindowState mainWin) {
+        if (inSizeCompatMode()) {
+            return "SIZE_COMPAT_MODE";
+        }
+        if (isLetterboxedForFixedOrientationAndAspectRatio()) {
+            return "FIXED_ORIENTATION";
+        }
+        if (mainWin.isLetterboxedForDisplayCutout()) {
+            return "DISPLAY_CUTOUT";
+        }
+        return "UNKNOWN_REASON";
     }
 
     void setAppTimeTracker(AppTimeTracker att) {
@@ -1700,7 +1733,7 @@
         keysPaused = false;
         inHistory = false;
         nowVisible = false;
-        mClientVisible = true;
+        super.setClientVisible(true);
         idle = false;
         hasBeenLaunched = false;
         mTaskSupervisor = supervisor;
@@ -2562,9 +2595,7 @@
      *         root task.
      */
     boolean supportsFreeform() {
-        return mAtmService.mSupportsFreeformWindowManagement
-                // Either the activity is resizable, or we allow size compat in freeform.
-                && (supportsMultiWindow() || mAtmService.mSizeCompatFreeform);
+        return mAtmService.mSupportsFreeformWindowManagement && supportsMultiWindow();
     }
 
     /**
@@ -3357,56 +3388,18 @@
         return mPendingRelaunchCount > 0;
     }
 
-    boolean shouldFreezeBounds() {
-        // For freeform windows, we can't freeze the bounds at the moment because this would make
-        // the resizing unresponsive.
-        if (task == null || task.inFreeformWindowingMode()) {
-            return false;
-        }
-
-        // We freeze the bounds while drag resizing to deal with the time between
-        // the divider/drag handle being released, and the handling it's new
-        // configuration. If we are relaunched outside of the drag resizing state,
-        // we need to be careful not to do this.
-        return task.isDragResizing();
-    }
-
     @VisibleForTesting
     void startRelaunching() {
         if (mPendingRelaunchCount == 0) {
             mRelaunchStartTime = SystemClock.elapsedRealtime();
         }
-        if (shouldFreezeBounds()) {
-            freezeBounds();
-        }
-
         clearAllDrawn();
 
         mPendingRelaunchCount++;
     }
 
-    /**
-     * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
-     * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
-     * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
-     * with a queue.
-     */
-    private void freezeBounds() {
-        mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
-
-        if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
-            // We didn't call prepareFreezingBounds on the task, so use the current value.
-            mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
-        } else {
-            mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
-        }
-        // Calling unset() to make it equal to Configuration.EMPTY.
-        task.mPreparedFrozenMergedConfig.unset();
-    }
-
     void finishRelaunching() {
         mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);
-        unfreezeBounds();
 
         if (mPendingRelaunchCount > 0) {
             mPendingRelaunchCount--;
@@ -3428,30 +3421,11 @@
         if (mPendingRelaunchCount == 0) {
             return;
         }
-        unfreezeBounds();
         mPendingRelaunchCount = 0;
         mRelaunchStartTime = 0;
     }
 
     /**
-     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
-     */
-    private void unfreezeBounds() {
-        if (mFrozenBounds.isEmpty()) {
-            return;
-        }
-        mFrozenBounds.remove();
-        if (!mFrozenMergedConfig.isEmpty()) {
-            mFrozenMergedConfig.remove();
-        }
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowState win = mChildren.get(i);
-            win.onUnfreezeBounds();
-        }
-        mWmService.mWindowPlacerLocked.performSurfacePlacement();
-    }
-
-    /**
      * Perform clean-up of service connections in an activity record.
      */
     private void cleanUpActivityServices() {
@@ -3799,7 +3773,7 @@
                     setVisibleRequested(true);
                     mVisibleSetFromTransferredStartingWindow = true;
                 }
-                setClientVisible(fromActivity.mClientVisible);
+                setClientVisible(fromActivity.isClientVisible());
 
                 if (fromActivity.isAnimating()) {
                     transferAnimation(fromActivity);
@@ -4447,6 +4421,7 @@
             return;
         }
         mVisibleRequested = visible;
+        setInsetsFrozen(!visible);
         if (app != null) {
             mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
         }
@@ -5899,18 +5874,15 @@
         return mReportedDrawn;
     }
 
-    boolean isClientVisible() {
-        return mClientVisible;
-    }
-
+    @Override
     void setClientVisible(boolean clientVisible) {
-        if (mClientVisible == clientVisible || (!clientVisible && mDeferHidingClient)) {
-            return;
-        }
+        // TODO(shell-transitions): Remove mDeferHidingClient once everything is shell-transitions.
+        //                          pip activities should just remain in clientVisible.
+        if (!clientVisible && mDeferHidingClient) return;
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible,
                 Debug.getCallers(5));
-        mClientVisible = clientVisible;
+        super.setClientVisible(clientVisible);
         sendAppVisibilityToClients();
     }
 
@@ -7454,8 +7426,7 @@
 
         final int containingAppWidth = containingAppBounds.width();
         final int containingAppHeight = containingAppBounds.height();
-        final float containingRatio = Math.max(containingAppWidth, containingAppHeight)
-                / (float) Math.min(containingAppWidth, containingAppHeight);
+        final float containingRatio = computeAspectRatio(containingAppBounds);
 
         int activityWidth = containingAppWidth;
         int activityHeight = containingAppHeight;
@@ -7519,6 +7490,18 @@
     }
 
     /**
+     * Returns the aspect ratio of the given {@code rect}.
+     */
+    private static float computeAspectRatio(Rect rect) {
+        final int width = rect.width();
+        final int height = rect.height();
+        if (width == 0 || height == 0) {
+            return 0;
+        }
+        return Math.max(width, height) / (float) Math.min(width, height);
+    }
+
+    /**
      * @return {@code true} if this activity was reparented to another display but
      *         {@link #ensureActivityConfiguration} is not called.
      */
@@ -8197,7 +8180,7 @@
         proto.write(TRANSLUCENT, !occludesParent());
         proto.write(VISIBLE, mVisible);
         proto.write(VISIBLE_REQUESTED, mVisibleRequested);
-        proto.write(CLIENT_VISIBLE, mClientVisible);
+        proto.write(CLIENT_VISIBLE, isClientVisible());
         proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
         proto.write(REPORTED_DRAWN, mReportedDrawn);
         proto.write(REPORTED_VISIBLE, reportedVisible);
@@ -8212,9 +8195,6 @@
         proto.write(STARTING_MOVED, startingMoved);
         proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
                 mVisibleSetFromTransferredStartingWindow);
-        for (Rect bounds : mFrozenBounds) {
-            bounds.dumpDebug(proto, FROZEN_BOUNDS);
-        }
 
         proto.write(STATE, mState.toString());
         proto.write(FRONT_OF_TASK, isRootOfTask());
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 94379b1..e858fe1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -348,13 +348,16 @@
     public final class ActivityTokens {
         private final @NonNull IBinder mActivityToken;
         private final @NonNull IBinder mAssistToken;
+        private final @NonNull IBinder mShareableActivityToken;
         private final @NonNull IApplicationThread mAppThread;
 
         public ActivityTokens(@NonNull IBinder activityToken,
-                @NonNull IBinder assistToken, @NonNull IApplicationThread appThread) {
+                @NonNull IBinder assistToken, @NonNull IApplicationThread appThread,
+                @NonNull IBinder shareableActivityToken) {
             mActivityToken = activityToken;
             mAssistToken = assistToken;
             mAppThread = appThread;
+            mShareableActivityToken = shareableActivityToken;
         }
 
         /**
@@ -372,6 +375,13 @@
         }
 
         /**
+         * @return The sharable activity token..
+         */
+        public @NonNull IBinder getShareableActivityToken() {
+            return mShareableActivityToken;
+        }
+
+        /**
          * @return The assist token.
          */
         public @NonNull IApplicationThread getApplicationThread() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index af032c1..0c77d9f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -58,7 +58,6 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
@@ -557,7 +556,6 @@
     boolean mSupportsPictureInPicture;
     boolean mSupportsMultiDisplay;
     boolean mForceResizableActivities;
-    boolean mSizeCompatFreeform;
     boolean mSupportsNonResizableMultiWindow;
 
     final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
@@ -788,8 +786,6 @@
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
         final boolean forceResizable = Settings.Global.getInt(
                 resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
-        final boolean sizeCompatFreeform = Settings.Global.getInt(
-                resolver, DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
         final boolean supportsNonResizableMultiWindow = Settings.Global.getInt(
                 resolver, DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1) != 0;
 
@@ -805,7 +801,6 @@
 
         synchronized (mGlobalLock) {
             mForceResizableActivities = forceResizable;
-            mSizeCompatFreeform = sizeCompatFreeform;
             mSupportsNonResizableMultiWindow = supportsNonResizableMultiWindow;
             final boolean multiWindowFormEnabled = freeformWindowManagement
                     || supportsSplitScreenMultiWindow
@@ -4047,17 +4042,9 @@
     int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
             boolean persistent, int userId) {
 
-        final DisplayContent defaultDisplay =
-                mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
-
         mTempConfig.setTo(getGlobalConfiguration());
         final int changes = mTempConfig.updateFrom(values);
         if (changes == 0) {
-            // Since calling to Activity.setRequestedOrientation leads to freezing the window with
-            // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
-            // performDisplayOverrideConfigUpdate in order to send the new display configuration
-            // (even if there are no actual changes) to unfreeze the window.
-            defaultDisplay.performDisplayOverrideConfigUpdate(values);
             return 0;
         }
 
@@ -5555,7 +5542,7 @@
                     return null;
                 }
                 return new ActivityTokens(activity.appToken, activity.assistToken,
-                        activity.app.getThread());
+                        activity.app.getThread(), activity.shareableActivityToken);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bf2aae8..bb0f1f0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -825,7 +825,7 @@
                         r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                         r.takeOptions(), dc.isNextTransitionForward(),
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
-                        r.createFixedRotationAdjustmentsIfNeeded()));
+                        r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken));
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 5b685b4..99289e0 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1305,7 +1305,7 @@
         if (isTransitionSet()) {
             clear();
             mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
-            mRemoteAnimationController = new RemoteAnimationController(mService,
+            mRemoteAnimationController = new RemoteAnimationController(mService, mDisplayContent,
                     remoteAnimationAdapter, mHandler);
         }
     }
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
new file mode 100644
index 0000000..13295e8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
+
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.view.ICrossWindowBlurEnabledListener;
+
+final class BlurController {
+
+    private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
+            mBlurEnabledListeners = new RemoteCallbackList<>();
+    private final Object mLock = new Object();
+    boolean mBlurEnabled;
+
+    BlurController() {
+        mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+    }
+
+    boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
+        if (listener == null) return false;
+        mBlurEnabledListeners.register(listener);
+        synchronized (mLock) {
+            return mBlurEnabled;
+        }
+    }
+
+    void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
+        if (listener == null) return;
+        mBlurEnabledListeners.unregister(listener);
+    }
+
+    private void updateBlurEnabled() {
+        // TODO: add other factors disabling blurs
+        final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+        synchronized (mLock) {
+            if (mBlurEnabled == newEnabled) {
+                return;
+            }
+            mBlurEnabled = newEnabled;
+            notifyBlurEnabledChanged(newEnabled);
+        }
+    }
+
+    private void notifyBlurEnabledChanged(boolean enabled) {
+        int i = mBlurEnabledListeners.beginBroadcast();
+        while (i > 0) {
+            i--;
+            ICrossWindowBlurEnabledListener listener =
+                    mBlurEnabledListeners.getBroadcastItem(i);
+            try {
+                listener.onCrossWindowBlurEnabledChanged(enabled);
+            } catch (RemoteException e) {
+            }
+        }
+        mBlurEnabledListeners.finishBroadcast();
+    }
+
+
+}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 309b5ec..62a0080 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -141,14 +141,17 @@
             mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
                     mMergedOverrideConfiguration);
         }
-        dispatchConfigurationToChildren();
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            dispatchConfigurationToChild(getChildAt(i), mFullConfiguration);
+        }
     }
 
-    void dispatchConfigurationToChildren() {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ConfigurationContainer child = getChildAt(i);
-            child.onConfigurationChanged(mFullConfiguration);
-        }
+    /**
+     * Dispatches the configuration to child when {@link #onConfigurationChanged(Configuration)} is
+     * called. This allows the derived classes to override how to dispatch the configuration.
+     */
+    void dispatchConfigurationToChild(E child, Configuration config) {
+        child.onConfigurationChanged(config);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 759b7fe..5ccf576 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -495,6 +495,21 @@
         return info;
     }
 
+    /**
+     * Gets the stable bounds of the DisplayArea, which is the bounds excluding insets for
+     * navigation bar, cutout, and status bar.
+     */
+    void getStableRect(Rect out) {
+        if (mDisplayContent == null) {
+            getBounds(out);
+            return;
+        }
+
+        // Intersect with the display stable bounds to get the DisplayArea stable bounds.
+        mDisplayContent.getStableRect(out);
+        out.intersect(getBounds());
+    }
+
     @Override
     public boolean providesMaxBounds() {
         return true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eff4ea6..119ffb7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2677,6 +2677,7 @@
         mWmService.mDisplayWindowSettings.setForcedSize(this, width, height);
     }
 
+    @Override
     void getStableRect(Rect out) {
         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         out.set(state.getDisplayFrame());
@@ -2943,10 +2944,6 @@
         return dockFrame.bottom - imeFrame.top;
     }
 
-    void prepareFreezingTaskBounds() {
-        forAllRootTasks(Task::prepareFreezingTaskBounds);
-    }
-
     void rotateBounds(@Rotation int oldRotation, @Rotation int newRotation, Rect inOutBounds) {
         // Get display bounds on oldRotation as parent bounds for the rotation.
         getBounds(mTmpRect, oldRotation);
@@ -3703,8 +3700,8 @@
         // app.
         assignWindowLayers(true /* setLayoutNeeded */);
         // 3. The z-order of IME might have been changed. Update the above insets state.
-        mInsetsStateController.updateAboveInsetsState(
-                mInputMethodWindow, true /* notifyInsetsChange */);
+        mInsetsStateController.updateAboveInsetsState(mInputMethodWindow,
+                mInsetsStateController.getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME));
         // 4. Update the IME control target to apply any inset change and animation.
         // 5. Reparent the IME container surface to either the input target app, or the IME window
         // parent.
@@ -4105,13 +4102,6 @@
      */
     void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
         if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
-            // Unfreeze the insets state of the frozen target when the animation finished if exists.
-            final Task task = wc.asTask();
-            if (task != null) {
-                task.forAllWindows(w -> {
-                    w.clearFrozenInsetsState();
-                }, true /* traverseTopToBottom */);
-            }
             removeImeSurfaceImmediately();
         }
     }
@@ -4833,7 +4823,7 @@
         }
         mNoAnimationNotifyOnTransitionFinished.clear();
 
-        mWallpaperController.hideDeferredWallpapersIfNeeded();
+        mWallpaperController.hideDeferredWallpapersIfNeededLegacy();
 
         onAppTransitionDone();
 
@@ -5272,13 +5262,6 @@
                 || windowingMode == WINDOWING_MODE_MULTI_WINDOW);
     }
 
-    static boolean canReuseExistingTask(int windowingMode, int activityType) {
-        // Existing Tasks can be reused if a new root task will be created anyway, or for the
-        // Dream - because there can only ever be one DreamActivity.
-        return alwaysCreateRootTask(windowingMode, activityType)
-                || activityType == ACTIVITY_TYPE_DREAM;
-    }
-
     @Nullable
     Task getFocusedRootTask() {
         return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedRootTask);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 32152ec..af9cdeb 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -69,6 +69,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
@@ -242,7 +243,7 @@
         }
     }
 
-    private final SystemGesturesPointerEventListener mSystemGestures;
+    private SystemGesturesPointerEventListener mSystemGestures;
 
     private volatile int mLidState = LID_ABSENT;
     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -384,7 +385,7 @@
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
 
-    private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+    private GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
 
     private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
 
@@ -448,119 +449,6 @@
 
         final Looper looper = UiThread.getHandler().getLooper();
         mHandler = new PolicyHandler(looper);
-        mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
-                new SystemGesturesPointerEventListener.Callbacks() {
-                    @Override
-                    public void onSwipeFromTop() {
-                        synchronized (mLock) {
-                            if (mStatusBar != null) {
-                                requestTransientBars(mStatusBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
-                        }
-                    }
-
-                    @Override
-                    public void onSwipeFromBottom() {
-                        synchronized (mLock) {
-                            if (mNavigationBar != null
-                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
-                                requestTransientBars(mNavigationBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
-                        }
-                    }
-
-                    @Override
-                    public void onSwipeFromRight() {
-                        final Region excludedRegion = Region.obtain();
-                        synchronized (mLock) {
-                            mDisplayContent.calculateSystemGestureExclusion(
-                                    excludedRegion, null /* outUnrestricted */);
-                            final boolean excluded =
-                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
-                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
-                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
-                                requestTransientBars(mNavigationBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
-                        }
-                        excludedRegion.recycle();
-                    }
-
-                    @Override
-                    public void onSwipeFromLeft() {
-                        final Region excludedRegion = Region.obtain();
-                        synchronized (mLock) {
-                            mDisplayContent.calculateSystemGestureExclusion(
-                                    excludedRegion, null /* outUnrestricted */);
-                            final boolean excluded =
-                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
-                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
-                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
-                                requestTransientBars(mNavigationBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
-                        }
-                        excludedRegion.recycle();
-                    }
-
-                    @Override
-                    public void onFling(int duration) {
-                        if (mService.mPowerManagerInternal != null) {
-                            mService.mPowerManagerInternal.setPowerBoost(
-                                    Boost.INTERACTION, duration);
-                        }
-                    }
-
-                    @Override
-                    public void onDebug() {
-                        // no-op
-                    }
-
-                    private WindowOrientationListener getOrientationListener() {
-                        final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
-                        return rotation != null ? rotation.getOrientationListener() : null;
-                    }
-
-                    @Override
-                    public void onDown() {
-                        final WindowOrientationListener listener = getOrientationListener();
-                        if (listener != null) {
-                            listener.onTouchStart();
-                        }
-                    }
-
-                    @Override
-                    public void onUpOrCancel() {
-                        final WindowOrientationListener listener = getOrientationListener();
-                        if (listener != null) {
-                            listener.onTouchEnd();
-                        }
-                    }
-
-                    @Override
-                    public void onMouseHoverAtTop() {
-                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
-                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
-                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
-                    }
-
-                    @Override
-                    public void onMouseHoverAtBottom() {
-                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
-                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
-                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
-                    }
-
-                    @Override
-                    public void onMouseLeaveFromEdge() {
-                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                    }
-                });
-        displayContent.registerPointerEventListener(mSystemGestures);
         mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
 
             private Runnable mAppTransitionPending = () -> {
@@ -616,7 +504,7 @@
         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
                 mService.mVrModeEnabled);
 
-        // TODO: Make it can take screenshot on external display
+        // TODO(b/180986447): Make it can take screenshot on external display
         mScreenshotHelper = displayContent.isDefaultDisplay
                 ? new ScreenshotHelper(mContext) : null;
 
@@ -640,16 +528,6 @@
         mRefreshRatePolicy = new RefreshRatePolicy(mService,
                 mDisplayContent.getDisplayInfo(),
                 mService.mHighRefreshRateDenylist);
-
-        mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
-                mContext, () -> {
-            synchronized (mLock) {
-                onConfigurationChanged();
-                mSystemGestures.onConfigurationChanged();
-                mDisplayContent.updateSystemGestureExclusion();
-            }
-        });
-        mHandler.post(mGestureNavigationSettingsObserver::register);
     }
 
     private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
@@ -668,12 +546,154 @@
     }
 
     void systemReady() {
-        mSystemGestures.systemReady();
         if (mService.mPointerLocationEnabled) {
             setPointerLocationEnabled(true);
         }
     }
 
+    @NonNull
+    private GestureNavigationSettingsObserver getGestureNavigationSettingsObserver() {
+        if (mGestureNavigationSettingsObserver == null) {
+            mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
+                    mContext, () -> {
+                synchronized (mLock) {
+                    onConfigurationChanged();
+                    getSystemGestures().onConfigurationChanged();
+                    mDisplayContent.updateSystemGestureExclusion();
+                }
+            });
+            mHandler.post(mGestureNavigationSettingsObserver::register);
+        }
+        return mGestureNavigationSettingsObserver;
+    }
+
+    @NonNull
+    private SystemGesturesPointerEventListener getSystemGestures() {
+        if (mSystemGestures == null) {
+            final Context gestureContext = mUiContext.createWindowContext(
+                    mDisplayContent.getDisplay(), TYPE_POINTER, null /* options */);
+            mSystemGestures = new SystemGesturesPointerEventListener(gestureContext, mHandler,
+                    new SystemGesturesPointerEventListener.Callbacks() {
+                        @Override
+                        public void onSwipeFromTop() {
+                            synchronized (mLock) {
+                                if (mStatusBar != null) {
+                                    requestTransientBars(mStatusBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
+                            }
+                        }
+
+                        @Override
+                        public void onSwipeFromBottom() {
+                            synchronized (mLock) {
+                                if (mNavigationBar != null
+                                        && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+                                    requestTransientBars(mNavigationBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
+                            }
+                        }
+
+                        @Override
+                        public void onSwipeFromRight() {
+                            final Region excludedRegion = Region.obtain();
+                            synchronized (mLock) {
+                                mDisplayContent.calculateSystemGestureExclusion(
+                                        excludedRegion, null /* outUnrestricted */);
+                                final boolean excluded = mSystemGestures
+                                        .currentGestureStartedInRegion(excludedRegion);
+                                if (mNavigationBar != null
+                                        && (mNavigationBarPosition == NAV_BAR_RIGHT
+                                        || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                    requestTransientBars(mNavigationBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
+                            }
+                            excludedRegion.recycle();
+                        }
+
+                        @Override
+                        public void onSwipeFromLeft() {
+                            final Region excludedRegion = Region.obtain();
+                            synchronized (mLock) {
+                                mDisplayContent.calculateSystemGestureExclusion(
+                                        excludedRegion, null /* outUnrestricted */);
+                                final boolean excluded = mSystemGestures
+                                        .currentGestureStartedInRegion(excludedRegion);
+                                if (mNavigationBar != null
+                                        && (mNavigationBarPosition == NAV_BAR_LEFT
+                                        || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                    requestTransientBars(mNavigationBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
+                            }
+                            excludedRegion.recycle();
+                        }
+
+                        @Override
+                        public void onFling(int duration) {
+                            if (mService.mPowerManagerInternal != null) {
+                                mService.mPowerManagerInternal.setPowerBoost(
+                                        Boost.INTERACTION, duration);
+                            }
+                        }
+
+                        @Override
+                        public void onDebug() {
+                            // no-op
+                        }
+
+                        private WindowOrientationListener getOrientationListener() {
+                            final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
+                            return rotation != null ? rotation.getOrientationListener() : null;
+                        }
+
+                        @Override
+                        public void onDown() {
+                            final WindowOrientationListener listener = getOrientationListener();
+                            if (listener != null) {
+                                listener.onTouchStart();
+                            }
+                        }
+
+                        @Override
+                        public void onUpOrCancel() {
+                            final WindowOrientationListener listener = getOrientationListener();
+                            if (listener != null) {
+                                listener.onTouchEnd();
+                            }
+                        }
+
+                        @Override
+                        public void onMouseHoverAtTop() {
+                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                            Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+                            msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
+                            mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+                        }
+
+                        @Override
+                        public void onMouseHoverAtBottom() {
+                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                            Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+                            msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
+                            mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+                        }
+
+                        @Override
+                        public void onMouseLeaveFromEdge() {
+                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                        }
+                    });
+            mDisplayContent.registerPointerEventListener(getSystemGestures());
+            if (mService.mSystemReady) {
+                mSystemGestures.systemReady();
+            }
+        }
+        return mSystemGestures;
+    }
+
     private int getDisplayId() {
         return mDisplayContent.getDisplayId();
     }
@@ -1455,8 +1475,7 @@
     }
 
     void onDisplayInfoChanged(DisplayInfo info) {
-        mSystemGestures.screenWidth = info.logicalWidth;
-        mSystemGestures.screenHeight = info.logicalHeight;
+        getSystemGestures().onDisplayInfoChanged(info);
     }
 
     private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) {
@@ -1969,7 +1988,7 @@
     public void onOverlayChangedLw() {
         updateCurrentUserResources();
         onConfigurationChanged();
-        mSystemGestures.onConfigurationChanged();
+        getSystemGestures().onConfigurationChanged();
     }
 
     /**
@@ -2040,10 +2059,10 @@
         }
 
         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
-        mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
-        mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
-        mNavButtonForcedVisible =
-                mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible();
+        final GestureNavigationSettingsObserver observer = getGestureNavigationSettingsObserver();
+        mLeftGestureInset = observer.getLeftSensitivity(res);
+        mRightGestureInset = observer.getRightSensitivity(res);
+        mNavButtonForcedVisible = observer.areNavigationButtonForcedVisible();
         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
         mNavigationBarAlwaysShowOnSideGesture =
                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
@@ -3056,7 +3075,7 @@
     }
 
     void release() {
-        mHandler.post(mGestureNavigationSettingsObserver::unregister);
+        mHandler.post(getGestureNavigationSettingsObserver()::unregister);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 1f7e152..316c20b 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -99,6 +99,9 @@
         mTask.forAllActivities(a -> {
             setActivityVisibilityState(a, starting, resumeTopActivity);
         });
+        if (mTask.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+            mTask.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
+        }
     }
 
     private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 27ef147..28c5a6d9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -410,15 +410,19 @@
             return;
         }
 
+        requestFocus(focusToken, focus.getName());
+    }
+
+    private void requestFocus(IBinder focusToken, String windowName) {
         if (focusToken == mInputFocus) {
             return;
         }
 
         mInputFocus = focusToken;
-        mInputTransaction.setFocusedWindow(mInputFocus, focus.getName(), mDisplayId);
-        EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + focus,
+        mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
+        EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
                 "reason=UpdateInputWindows");
-        ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", focus);
+        ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName);
     }
 
     void setFocusedAppLw(ActivityRecord newApp) {
@@ -470,6 +474,8 @@
 
         boolean mInDrag;
 
+        private boolean mRecentsAnimationFocusOverride;
+
         private void updateInputWindows(boolean inDrag) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
 
@@ -485,10 +491,16 @@
             mInDrag = inDrag;
 
             resetInputConsumers(mInputTransaction);
-
+            mRecentsAnimationFocusOverride = false;
             mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
 
-            updateInputFocusRequest();
+            if (mRecentsAnimationFocusOverride) {
+                requestFocus(mRecentsAnimationInputConsumer.mWindowHandle.token,
+                        mRecentsAnimationInputConsumer.mName);
+            } else {
+                updateInputFocusRequest();
+            }
+
 
             if (!mUpdateInputWindowsImmediately) {
                 mDisplayContent.getPendingTransaction().merge(mInputTransaction);
@@ -526,6 +538,7 @@
                         mRecentsAnimationInputConsumer.mWindowHandle)) {
                     mRecentsAnimationInputConsumer.show(mInputTransaction, w.mActivityRecord);
                     mAddRecentsAnimationInputConsumerHandle = false;
+                    mRecentsAnimationFocusOverride = true;
                 }
             }
 
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 75176df..a971794 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -124,7 +124,8 @@
                 ? provider.getSource().getType() : ITYPE_INVALID;
         return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
                 target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() :
-                target.mAboveInsetsState);
+                        (target.mAttrs.receiveInsetsIgnoringZOrder ? mState :
+                         target.mAboveInsetsState));
     }
 
     InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index e18516d..62c155a 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -540,7 +540,7 @@
             setStatusBarState(mLockTaskModeState, userId);
             setKeyguardState(mLockTaskModeState, userId);
             if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
-                lockKeyguardIfNeeded();
+                lockKeyguardIfNeeded(userId);
             }
             if (getDevicePolicyManager() != null) {
                 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
@@ -886,15 +886,15 @@
      * Helper method for locking the device immediately. This may be necessary when the device
      * leaves the pinned mode.
      */
-    private void lockKeyguardIfNeeded() {
-        if (shouldLockKeyguard()) {
+    private void lockKeyguardIfNeeded(int userId) {
+        if (shouldLockKeyguard(userId)) {
             mWindowManager.lockNow(null);
             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
             getLockPatternUtils().requireCredentialEntry(USER_ALL);
         }
     }
 
-    private boolean shouldLockKeyguard() {
+    private boolean shouldLockKeyguard(int userId) {
         // This functionality should be kept consistent with
         // com.android.settings.security.ScreenPinningSettings (see b/127605586)
         try {
@@ -904,7 +904,7 @@
         } catch (Settings.SettingNotFoundException e) {
             // Log to SafetyNet for b/127605586
             android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, "");
-            return getLockPatternUtils().isSecure(USER_CURRENT);
+            return getLockPatternUtils().isSecure(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index 5d6d513..e6e866d 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -16,6 +16,12 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
+import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
+
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -26,6 +32,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.policy.WindowManagerPolicy;
@@ -35,7 +42,7 @@
 
 class NonAppWindowAnimationAdapter implements AnimationAdapter {
 
-    private final WindowState mWindow;
+    private final WindowContainer mWindow;
     private RemoteAnimationTarget mTarget;
     private SurfaceControl mCapturedLeash;
 
@@ -47,22 +54,43 @@
         return false;
     }
 
-    NonAppWindowAnimationAdapter(WindowState w,
-            long durationHint, long statusBarTransitionDelay) {
+    NonAppWindowAnimationAdapter(WindowContainer w, long durationHint,
+            long statusBarTransitionDelay) {
         mWindow = w;
         mDurationHint = durationHint;
         mStatusBarTransitionDelay = statusBarTransitionDelay;
     }
 
+    static RemoteAnimationTarget[] startNonAppWindowAnimations(WindowManagerService service,
+            DisplayContent displayContent, @WindowManager.TransitionOldType int transit,
+            long durationHint, long statusBarTransitionDelay) {
+        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
+        if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
+                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
+            startNonAppWindowAnimationsForKeyguardExit(
+                    service, durationHint, statusBarTransitionDelay, targets);
+        } else if (transit == TRANSIT_OLD_TASK_OPEN || transit == TRANSIT_OLD_TASK_TO_FRONT
+                || transit == TRANSIT_OLD_WALLPAPER_CLOSE) {
+            final boolean shouldAttachNavBarToApp =
+                    displayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
+                            && service.getRecentsAnimationController() == null
+                            && displayContent.getFixedRotationAnimationController() == null;
+            if (shouldAttachNavBarToApp) {
+                startNavigationBarWindowAnimation(
+                        displayContent, durationHint, statusBarTransitionDelay, targets);
+            }
+        }
+        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+    }
+
     /**
      * Creates and starts remote animations for all the visible non app windows.
      *
      * @return RemoteAnimationTarget[] targets for all the visible non app windows
      */
-    public static RemoteAnimationTarget[] startNonAppWindowAnimationsForKeyguardExit(
-            WindowManagerService service, long durationHint, long statusBarTransitionDelay) {
-        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
-
+    private static void startNonAppWindowAnimationsForKeyguardExit(WindowManagerService service,
+            long durationHint, long statusBarTransitionDelay,
+            ArrayList<RemoteAnimationTarget> targets) {
         final WindowManagerPolicy policy = service.mPolicy;
         service.mRoot.forAllWindows(nonAppWindow -> {
             if (nonAppWindow.mActivityRecord == null && policy.canBeHiddenByKeyguardLw(nonAppWindow)
@@ -74,7 +102,22 @@
                 targets.add(nonAppAdapter.createRemoteAnimationTarget());
             }
         }, true /* traverseTopToBottom */);
-        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
+    }
+
+    /**
+     * Creates and starts remote animation for the navigation bar windows.
+     *
+     * @return RemoteAnimationTarget[] targets for all the visible non app windows
+     */
+    private static void startNavigationBarWindowAnimation(DisplayContent displayContent,
+            long durationHint, long statusBarTransitionDelay,
+            ArrayList<RemoteAnimationTarget> targets) {
+        final WindowState navWindow = displayContent.getDisplayPolicy().getNavigationBar();
+        final NonAppWindowAnimationAdapter nonAppAdapter = new NonAppWindowAnimationAdapter(
+                navWindow.mToken, durationHint, statusBarTransitionDelay);
+        navWindow.mToken.startAnimation(navWindow.mToken.getPendingTransaction(),
+                nonAppAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
+        targets.add(nonAppAdapter.createRemoteAnimationTarget());
     }
 
     /**
@@ -84,7 +127,7 @@
         mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
                 new Rect(), null, mWindow.getPrefixOrderIndex(), mWindow.getLastSurfacePosition(),
                 mWindow.getBounds(), null, mWindow.getWindowConfiguration(), true, null, null,
-                null);
+                null, mWindow.getWindowType());
         return mTarget;
     }
 
@@ -120,8 +163,8 @@
     @Override
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix);
-        pw.print("token=");
-        pw.println(mWindow.mToken);
+        pw.print("window=");
+        pw.println(mWindow);
         if (mTarget != null) {
             pw.print(prefix);
             pw.println("Target:");
diff --git a/services/core/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
index 08de9b0..9bc7e93 100644
--- a/services/core/java/com/android/server/wm/PointerEventDispatcher.java
+++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.input.InputManagerService.ENABLE_PER_WINDOW_INPUT_ROTATION;
 
+import android.graphics.Point;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
@@ -35,6 +36,7 @@
     private PointerEventListener[] mListenersArray = new PointerEventListener[0];
 
     private final DisplayContent mDisplayContent;
+    private final Point mTmpSize = new Point();
 
     public PointerEventDispatcher(InputChannel inputChannel, DisplayContent dc) {
         super(inputChannel, UiThread.getHandler().getLooper());
@@ -48,12 +50,12 @@
                     && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                 MotionEvent motionEvent = (MotionEvent) event;
                 if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
-                    int rotation = mDisplayContent.getRotation();
+                    final int rotation = mDisplayContent.getRotation();
                     if (rotation != Surface.ROTATION_0) {
+                        mDisplayContent.getDisplay().getRealSize(mTmpSize);
                         motionEvent = MotionEvent.obtain(motionEvent);
-                        motionEvent.transform(MotionEvent.createRotateMatrix(rotation,
-                                mDisplayContent.getDisplayMetrics().widthPixels,
-                                mDisplayContent.getDisplayMetrics().heightPixels));
+                        motionEvent.transform(MotionEvent.createRotateMatrix(
+                                rotation, mTmpSize.x, mTmpSize.y));
                     }
                 }
                 PointerEventListener[] listeners;
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 42cb96f..31663b7 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
@@ -60,6 +57,7 @@
     private static final long TIMEOUT_MS = 2000;
 
     private final WindowManagerService mService;
+    private final DisplayContent mDisplayContent;
     private final RemoteAnimationAdapter mRemoteAnimationAdapter;
     private final ArrayList<RemoteAnimationRecord> mPendingAnimations = new ArrayList<>();
     private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
@@ -72,9 +70,10 @@
     private boolean mCanceled;
     private boolean mLinkedToDeathOfRunner;
 
-    RemoteAnimationController(WindowManagerService service,
+    RemoteAnimationController(WindowManagerService service, DisplayContent displayContent,
             RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
         mService = service;
+        mDisplayContent = displayContent;
         mRemoteAnimationAdapter = remoteAnimationAdapter;
         mHandler = handler;
     }
@@ -221,12 +220,11 @@
     private RemoteAnimationTarget[] createNonAppWindowAnimations(
             @WindowManager.TransitionOldType int transit) {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createNonAppWindowAnimations()");
-        return (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER)
-                ? NonAppWindowAnimationAdapter.startNonAppWindowAnimationsForKeyguardExit(mService,
+        return NonAppWindowAnimationAdapter.startNonAppWindowAnimations(mService,
+                    mDisplayContent,
+                    transit,
                     mRemoteAnimationAdapter.getDuration(),
-                    mRemoteAnimationAdapter.getStatusBarTransitionDelay())
-                : new RemoteAnimationTarget[0];
+                    mRemoteAnimationAdapter.getStatusBarTransitionDelay());
     }
 
     private void onAnimationFinished() {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3f9ea1f..0e8cadb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -650,28 +650,12 @@
     }
 
     @Override
-    void dispatchConfigurationToChildren() {
-        final Configuration configuration = getConfiguration();
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final DisplayContent displayContent = getChildAt(i);
-            if (displayContent.isDefaultDisplay) {
-                // The global configuration is also the override configuration of default display.
-                displayContent.performDisplayOverrideConfigUpdate(configuration);
-            } else {
-                displayContent.onConfigurationChanged(configuration);
-            }
-        }
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
-        prepareFreezingTaskBounds();
-        super.onConfigurationChanged(newParentConfig);
-    }
-
-    private void prepareFreezingTaskBounds() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            mChildren.get(i).prepareFreezingTaskBounds();
+    void dispatchConfigurationToChild(DisplayContent child, Configuration config) {
+        if (child.isDefaultDisplay) {
+            // The global configuration is also the override configuration of default display.
+            child.performDisplayOverrideConfigUpdate(config);
+        } else {
+            child.onConfigurationChanged(config);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index f3859b4..a98a478 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -126,11 +126,17 @@
                 Slog.w(TAG, "Cannot create GestureDetector, display removed:" + displayId);
                 return;
             }
+            onDisplayInfoChanged(info);
             mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) {
             };
         });
     }
 
+    void onDisplayInfoChanged(DisplayInfo info) {
+        screenWidth = info.logicalWidth;
+        screenHeight = info.logicalHeight;
+    }
+
     @Override
     public void onPointerEvent(MotionEvent event) {
         if (mGestureDetector != null && event.isTouchEvent()) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7085156..f850e85 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -21,6 +21,7 @@
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -498,9 +499,6 @@
     // TODO: Make final
     int mUserId;
 
-    final Rect mPreparedFrozenBounds = new Rect();
-    final Configuration mPreparedFrozenMergedConfig = new Configuration();
-
     // Id of the previous display the root task was on.
     int mPrevDisplayId = INVALID_DISPLAY;
 
@@ -835,6 +833,9 @@
     // Tracking cookie for the creation of this task.
     IBinder mLaunchCookie;
 
+    // The task will be removed when TaskOrganizer, which is managing the task, is destroyed.
+    boolean mRemoveWithTaskOrganizer;
+
     private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -846,7 +847,8 @@
             boolean supportsPictureInPicture, boolean _realActivitySuspended,
             boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
-            boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear) {
+            boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
+            boolean _removeWithTaskOrganizer) {
         super(atmService.mWindowManager);
 
         mAtmService = atmService;
@@ -905,6 +907,7 @@
         mCreatedByOrganizer = _createdByOrganizer;
         mLaunchCookie = _launchCookie;
         mDeferTaskAppear = _deferTaskAppear;
+        mRemoveWithTaskOrganizer = _removeWithTaskOrganizer;
         EventLogTags.writeWmTaskCreated(mTaskId, isRootTask() ? INVALID_TASK_ID : getRootTaskId());
     }
 
@@ -1177,10 +1180,6 @@
                 mTaskSupervisor.mNoAnimActivities.add(topActivity);
             }
 
-            // We might trigger a configuration change. Save the current task bounds for freezing.
-            // TODO: Should this call be moved inside the resize method in WM?
-            toRootTask.prepareFreezingTaskBounds();
-
             if (toRootTaskWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                     && moveRootTaskMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) {
                 // Move recents to front so it is not behind root home task when going into docked
@@ -1255,10 +1254,13 @@
      * @param info The activity info which could be different from {@code r.info} if set.
      */
     void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
-        mCallingUid = r.launchedFromUid;
-        mCallingPackage = r.launchedFromPackage;
-        mCallingFeatureId = r.launchedFromFeatureId;
-        setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+        if (this.intent == null || !mNeverRelinquishIdentity) {
+            mCallingUid = r.launchedFromUid;
+            mCallingPackage = r.launchedFromPackage;
+            mCallingFeatureId = r.launchedFromFeatureId;
+            setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+            return;
+        }
         setLockTaskAuth(r);
     }
 
@@ -1266,13 +1268,7 @@
     private void setIntent(Intent _intent, ActivityInfo info) {
         if (!isLeafTask()) return;
 
-        if (intent == null) {
-            mNeverRelinquishIdentity =
-                    (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
-        } else if (mNeverRelinquishIdentity) {
-            return;
-        }
-
+        mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
         affinity = info.taskAffinity;
         if (intent == null) {
             // If this task already has an intent associated with it, don't set the root
@@ -2836,8 +2832,6 @@
                     windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
             if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
                     && candidateWindowingMode != WINDOWING_MODE_PINNED
-                    && (candidateWindowingMode != WINDOWING_MODE_FREEFORM
-                            || !mTaskSupervisor.mService.mSizeCompatFreeform)
                     && !mTaskSupervisor.mService.mSupportsNonResizableMultiWindow) {
                 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
                         WINDOWING_MODE_FULLSCREEN);
@@ -3363,15 +3357,6 @@
         return isResizeable();
     }
 
-    /**
-     * Prepares the task bounds to be frozen with the current size. See
-     * {@link ActivityRecord#freezeBounds}.
-     */
-    void prepareFreezingBounds() {
-        mPreparedFrozenBounds.set(getBounds());
-        mPreparedFrozenMergedConfig.setTo(getConfiguration());
-    }
-
     @Override
     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
             Rect outSurfaceInsets) {
@@ -5058,6 +5043,10 @@
             }
         } else {
             // No longer managed by any organizer.
+            final TaskDisplayArea taskDisplayArea = getDisplayArea();
+            if (taskDisplayArea != null) {
+                taskDisplayArea.removeLaunchRootTask(this);
+            }
             setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
             if (mCreatedByOrganizer) {
                 removeImmediately("setTaskOrganizer");
@@ -7361,6 +7350,7 @@
         return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
                 toTop, null /*activity*/, null /*source*/, null /*options*/);
     }
+
     // TODO: Can be removed once we change callpoints creating root tasks to be creating tasks.
     /** Either returns this current task to be re-used or creates a new child task. */
     Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession,
@@ -7368,7 +7358,7 @@
             ActivityRecord source, ActivityOptions options) {
 
         Task task;
-        if (DisplayContent.canReuseExistingTask(getWindowingMode(), getActivityType())) {
+        if (canReuseAsLeafTask()) {
             // This root task will only contain one task, so just return itself since all root
             // tasks ara now tasks and all tasks are now root tasks.
             task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity);
@@ -7403,10 +7393,24 @@
         return task;
     }
 
+    /** Return {@code true} if this task can be reused as leaf task. */
+    private boolean canReuseAsLeafTask() {
+        // Cannot be reused as leaf task if this task is created by organizer or having child tasks.
+        if (mCreatedByOrganizer || !isLeafTask()) {
+            return false;
+        }
+
+        // Existing Tasks can be reused if a new root task will be created anyway, or for the
+        // Dream - because there can only ever be one DreamActivity.
+        final int windowingMode = getWindowingMode();
+        final int activityType = getActivityType();
+        return DisplayContent.alwaysCreateRootTask(windowingMode, activityType)
+                || activityType == ACTIVITY_TYPE_DREAM;
+    }
+
     void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) {
         Task task = child.asTask();
         try {
-
             if (task != null) {
                 task.setForceShowForAllUsers(showForAllUsers);
             }
@@ -7499,10 +7503,6 @@
         });
     }
 
-    void prepareFreezingTaskBounds() {
-        forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */);
-    }
-
     private int setBounds(Rect existing, Rect bounds) {
         if (equivalentBounds(existing, bounds)) {
             return BOUNDS_CHANGE_NONE;
@@ -7845,6 +7845,7 @@
         private IBinder mLaunchCookie;
         private boolean mOnTop;
         private boolean mHasBeenVisible;
+        private boolean mRemoveWithTaskOrganizer;
 
         Builder(ActivityTaskManagerService atm) {
             mAtmService = atm;
@@ -8140,6 +8141,9 @@
             mCallingPackage = mActivityInfo.packageName;
             mResizeMode = mActivityInfo.resizeMode;
             mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
+            if (mActivityOptions != null) {
+                mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer();
+            }
 
             final Task task = buildInner();
             task.mHasBeenVisible = mHasBeenVisible;
@@ -8178,7 +8182,7 @@
                     mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
                     mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
                     mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
-                    mLaunchCookie, mDeferTaskAppear);
+                    mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index badd7fd..76869e5 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1135,12 +1135,7 @@
                     "Can't set not mCreatedByOrganizer as launch root tr=" + rootTask);
         }
 
-        LaunchRootTaskDef def = null;
-        for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
-            if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue;
-            def = mLaunchRootTasks.get(i);
-        }
-
+        LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask);
         if (def != null) {
             // Remove so we add to the end of the list.
             mLaunchRootTasks.remove(def);
@@ -1156,6 +1151,23 @@
         }
     }
 
+    void removeLaunchRootTask(Task rootTask) {
+        LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask);
+        if (def != null) {
+            mLaunchRootTasks.remove(def);
+        }
+    }
+
+    private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) {
+        LaunchRootTaskDef def = null;
+        for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
+            if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue;
+            def = mLaunchRootTasks.get(i);
+            break;
+        }
+        return def;
+    }
+
     Task getLaunchRootTask(int windowingMode, int activityType, ActivityOptions options) {
         // Try to use the launch root task in options if available.
         if (options != null) {
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 82d9c21..ee5c1f01 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -165,6 +165,10 @@
         // hasInitialBounds is set if either activity options or layout has specified bounds. If
         // that's set we'll skip some adjustments later to avoid overriding the initial bounds.
         boolean hasInitialBounds = false;
+        // hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow is set if the outParams.mBounds
+        // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
+        // different, we should recalculating the bounds.
+        boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow = false;
         final boolean canApplyFreeformPolicy = canApplyFreeformWindowPolicy(display, launchMode);
         if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
                 && (canApplyFreeformPolicy || canApplyPipWindowPolicy(launchMode))) {
@@ -180,11 +184,13 @@
         } else if (launchMode == WINDOWING_MODE_FULLSCREEN) {
             if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds);
         } else if (layout != null && canApplyFreeformPolicy) {
-            getLayoutBounds(display, root, layout, mTmpBounds);
+            mTmpBounds.set(currentParams.mBounds);
+            getLayoutBounds(suggestedDisplayArea, root, layout, mTmpBounds);
             if (!mTmpBounds.isEmpty()) {
                 launchMode = WINDOWING_MODE_FREEFORM;
                 outParams.mBounds.set(mTmpBounds);
                 hasInitialBounds = true;
+                hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow = true;
                 if (DEBUG) appendLog("bounds-from-layout=" + outParams.mBounds);
             } else {
                 if (DEBUG) appendLog("empty-window-layout");
@@ -240,6 +246,11 @@
         // such as orientation. Otherwise, the app is forcefully launched in maximized. The rest of
         // this step is to define the default policy when there is no initial bounds or a fully
         // resolved current params from callers.
+
+        // hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay is set if the outParams.mBounds
+        // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
+        // different, we should recalcuating the bounds.
+        boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = false;
         if (display.inFreeformWindowingMode()) {
             if (launchMode == WINDOWING_MODE_PINNED) {
                 if (DEBUG) appendLog("picture-in-picture");
@@ -247,8 +258,9 @@
                 if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea)) {
                     launchMode = WINDOWING_MODE_FREEFORM;
                     if (outParams.mBounds.isEmpty()) {
-                        getTaskBounds(root, display, layout, launchMode, hasInitialBounds,
-                                outParams.mBounds);
+                        getTaskBounds(root, suggestedDisplayArea, layout, launchMode,
+                                hasInitialBounds, outParams.mBounds);
+                        hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = true;
                     }
                     if (DEBUG) appendLog("unresizable-freeform");
                 } else {
@@ -287,6 +299,20 @@
                 mTmpDisplayArea = displayArea;
                 return true;
             });
+            // We may need to recalculate the bounds if the new TaskDisplayArea is different from
+            // the suggested one we used to calculate the bounds.
+            if (mTmpDisplayArea != null && mTmpDisplayArea != suggestedDisplayArea) {
+                if (hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow) {
+                    outParams.mBounds.setEmpty();
+                    getLayoutBounds(mTmpDisplayArea, root, layout, outParams.mBounds);
+                    hasInitialBounds = !outParams.mBounds.isEmpty();
+                } else if (hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay) {
+                    outParams.mBounds.setEmpty();
+                    getTaskBounds(root, mTmpDisplayArea, layout, launchMode,
+                            hasInitialBounds, outParams.mBounds);
+                }
+            }
+
             if (mTmpDisplayArea != null) {
                 taskDisplayArea = mTmpDisplayArea;
                 mTmpDisplayArea = null;
@@ -302,7 +328,6 @@
         if (phase == PHASE_DISPLAY_AREA) {
             return RESULT_CONTINUE;
         }
-        // TODO(b/152116619): Update the usages of display to use taskDisplayArea below.
 
         // STEP 4: Determine final launch bounds based on resolved windowing mode and activity
         // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is
@@ -312,13 +337,13 @@
         // We skip making adjustments if the params are fully resolved from previous results.
         if (fullyResolvedCurrentParam) {
             if (resolvedMode == WINDOWING_MODE_FREEFORM) {
-                // Make sure bounds are in the display if it's possibly in a different display/area.
+                // Make sure bounds are in the displayArea.
                 if (currentParams.mPreferredTaskDisplayArea != taskDisplayArea) {
-                    adjustBoundsToFitInDisplay(display, outParams.mBounds);
+                    adjustBoundsToFitInDisplayArea(taskDisplayArea, outParams.mBounds);
                 }
                 // Even though we want to keep original bounds, we still don't want it to stomp on
                 // an existing task.
-                adjustBoundsToAvoidConflictInDisplay(display, outParams.mBounds);
+                adjustBoundsToAvoidConflictInDisplayArea(taskDisplayArea, outParams.mBounds);
             }
         } else if (taskDisplayArea.inFreeformWindowingMode()) {
             if (source != null && source.inFreeformWindowingMode()
@@ -327,9 +352,10 @@
                     && source.getDisplayArea() == taskDisplayArea) {
                 // Set bounds to be not very far from source activity.
                 cascadeBounds(source.getConfiguration().windowConfiguration.getBounds(),
-                        display, outParams.mBounds);
+                        taskDisplayArea, outParams.mBounds);
             }
-            getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
+            getTaskBounds(root, taskDisplayArea, layout, resolvedMode, hasInitialBounds,
+                    outParams.mBounds);
         }
         return RESULT_CONTINUE;
     }
@@ -499,30 +525,36 @@
                 && launchMode == WINDOWING_MODE_PINNED;
     }
 
-    private void getLayoutBounds(@NonNull DisplayContent display, @NonNull ActivityRecord root,
-            @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
+    private void getLayoutBounds(@NonNull TaskDisplayArea displayArea, @NonNull ActivityRecord root,
+            @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect inOutBounds) {
         final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
         final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) {
-            outBounds.setEmpty();
+            inOutBounds.setEmpty();
             return;
         }
 
         // Use stable frame instead of raw frame to avoid launching freeform windows on top of
         // stable insets, which usually are system widgets such as sysbar & navbar.
-        final Rect displayStableBounds = mTmpStableBounds;
-        display.getStableRect(displayStableBounds);
-        final int defaultWidth = displayStableBounds.width();
-        final int defaultHeight = displayStableBounds.height();
+        final Rect stableBounds = mTmpStableBounds;
+        displayArea.getStableRect(stableBounds);
+        final int defaultWidth = stableBounds.width();
+        final int defaultHeight = stableBounds.height();
 
         int width;
         int height;
         if (!windowLayout.hasSpecifiedSize()) {
-            outBounds.setEmpty();
-            getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM,
-                    /* hasInitialBounds */ false, outBounds);
-            width = outBounds.width();
-            height = outBounds.height();
+            if (!inOutBounds.isEmpty()) {
+                // If the bounds is resolved already and WindowLayout doesn't have any opinion on
+                // its size, use the already resolved size and apply the gravity to it.
+                width = inOutBounds.width();
+                height = inOutBounds.height();
+            } else {
+                getTaskBounds(root, displayArea, windowLayout, WINDOWING_MODE_FREEFORM,
+                        /* hasInitialBounds */ false, inOutBounds);
+                width = inOutBounds.width();
+                height = inOutBounds.height();
+            }
         } else {
             width = defaultWidth;
             if (windowLayout.width > 0 && windowLayout.width < defaultWidth) {
@@ -563,26 +595,21 @@
                 fractionOfVerticalOffset = 0.5f;
         }
 
-        outBounds.set(0, 0, width, height);
-        outBounds.offset(displayStableBounds.left, displayStableBounds.top);
+        inOutBounds.set(0, 0, width, height);
+        inOutBounds.offset(stableBounds.left, stableBounds.top);
         final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
         final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
-        outBounds.offset(xOffset, yOffset);
+        inOutBounds.offset(xOffset, yOffset);
     }
 
     private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity,
             TaskDisplayArea displayArea) {
-        // TODO(176061101): Migrate |mSizeCompatFreeform| to |mSupportsNonResizableMultiWindow|.
-        if (!mSupervisor.mService.mSizeCompatFreeform || activity.isResizeable()) {
-            return false;
-        }
-        final DisplayContent display = displayArea.getDisplayContent();
-        if (display == null) {
+        if (!mSupervisor.mService.mSupportsNonResizableMultiWindow || activity.isResizeable()) {
             return false;
         }
 
         final int displayOrientation = orientationFromBounds(displayArea.getBounds());
-        final int activityOrientation = resolveOrientation(activity, display,
+        final int activityOrientation = resolveOrientation(activity, displayArea,
                 displayArea.getBounds());
         if (displayArea.getWindowingMode() == WINDOWING_MODE_FREEFORM
                 && displayOrientation != activityOrientation) {
@@ -632,19 +659,19 @@
         return orientation;
     }
 
-    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull DisplayContent display,
+    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull TaskDisplayArea displayArea,
             @NonNull Rect outBounds) {
         outBounds.set(srcBounds);
-        float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+        float density = (float) displayArea.getConfiguration().densityDpi / DENSITY_DEFAULT;
         final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
 
-        display.getBounds(mTmpBounds);
+        displayArea.getBounds(mTmpBounds);
         final int dx = Math.min(defaultOffset, Math.max(0, mTmpBounds.right - srcBounds.right));
         final int dy = Math.min(defaultOffset, Math.max(0, mTmpBounds.bottom - srcBounds.bottom));
         outBounds.offset(dx, dy);
     }
 
-    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull DisplayContent display,
+    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull TaskDisplayArea displayArea,
             @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
             @NonNull Rect inOutBounds) {
         if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
@@ -663,7 +690,7 @@
             return;
         }
 
-        final int orientation = resolveOrientation(root, display, inOutBounds);
+        final int orientation = resolveOrientation(root, displayArea, inOutBounds);
         if (orientation != SCREEN_ORIENTATION_PORTRAIT
                 && orientation != SCREEN_ORIENTATION_LANDSCAPE) {
             throw new IllegalStateException(
@@ -672,7 +699,7 @@
         }
 
         // First we get the default size we want.
-        getDefaultFreeformSize(display, layout, orientation, mTmpBounds);
+        getDefaultFreeformSize(displayArea, layout, orientation, mTmpBounds);
         if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
             // We're here because either input parameters specified initial bounds, or the suggested
             // bounds have the same size of the default freeform size. We should use the suggested
@@ -682,22 +709,24 @@
                 if (DEBUG) appendLog("freeform-size-orientation-match=" + inOutBounds);
             } else {
                 // Meh, orientation doesn't match. Let's rotate inOutBounds in-place.
-                centerBounds(display, inOutBounds.height(), inOutBounds.width(), inOutBounds);
+                centerBounds(displayArea, inOutBounds.height(), inOutBounds.width(),
+                        inOutBounds);
                 if (DEBUG) appendLog("freeform-orientation-mismatch=" + inOutBounds);
             }
         } else {
             // We are here either because there is no suggested bounds, or the suggested bounds is
             // a cascade from source activity. We should use the default freeform size and center it
-            // to the center of suggested bounds (or the display if no suggested bounds). The
-            // default size might be too big to center to source activity bounds in display, so we
-            // may need to move it back to the display.
-            centerBounds(display, mTmpBounds.width(), mTmpBounds.height(), inOutBounds);
-            adjustBoundsToFitInDisplay(display, inOutBounds);
+            // to the center of suggested bounds (or the displayArea if no suggested bounds). The
+            // default size might be too big to center to source activity bounds in displayArea, so
+            // we may need to move it back to the displayArea.
+            centerBounds(displayArea, mTmpBounds.width(), mTmpBounds.height(),
+                    inOutBounds);
+            adjustBoundsToFitInDisplayArea(displayArea, inOutBounds);
             if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds);
         }
 
         // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
-        adjustBoundsToAvoidConflictInDisplay(display, inOutBounds);
+        adjustBoundsToAvoidConflictInDisplayArea(displayArea, inOutBounds);
     }
 
     private int convertOrientationToScreenOrientation(int orientation) {
@@ -711,13 +740,14 @@
         }
     }
 
-    private int resolveOrientation(@NonNull ActivityRecord root, @NonNull DisplayContent display,
-            @NonNull Rect bounds) {
+    private int resolveOrientation(@NonNull ActivityRecord root,
+            @NonNull TaskDisplayArea displayArea, @NonNull Rect bounds) {
         int orientation = resolveOrientation(root);
 
         if (orientation == SCREEN_ORIENTATION_LOCKED) {
             orientation = bounds.isEmpty()
-                    ? convertOrientationToScreenOrientation(display.getConfiguration().orientation)
+                    ? convertOrientationToScreenOrientation(
+                            displayArea.getConfiguration().orientation)
                     : orientationFromBounds(bounds);
             if (DEBUG) {
                 appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
@@ -737,19 +767,17 @@
         return orientation;
     }
 
-    private void getDefaultFreeformSize(@NonNull DisplayContent display,
+    private void getDefaultFreeformSize(@NonNull TaskDisplayArea displayArea,
             @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
-        // Default size, which is letterboxing/pillarboxing in display. That's to say the large
-        // dimension of default size is the small dimension of display size, and the small dimension
-        // of default size is calculated to keep the same aspect ratio as the display's. Here we use
-        // stable bounds of displays because that indicates the area that isn't occupied by system
-        // widgets (e.g. sysbar and navbar).
-        final Rect displayStableBounds = mTmpStableBounds;
-        display.getStableRect(displayStableBounds);
-        final int portraitHeight =
-                Math.min(displayStableBounds.width(), displayStableBounds.height());
-        final int otherDimension =
-                Math.max(displayStableBounds.width(), displayStableBounds.height());
+        // Default size, which is letterboxing/pillarboxing in displayArea. That's to say the large
+        // dimension of default size is the small dimension of displayArea size, and the small
+        // dimension of default size is calculated to keep the same aspect ratio as the
+        // displayArea's. Here we use stable bounds of displayArea because that indicates the area
+        // that isn't occupied by system widgets (e.g. sysbar and navbar).
+        final Rect stableBounds = mTmpStableBounds;
+        displayArea.getStableRect(stableBounds);
+        final int portraitHeight = Math.min(stableBounds.width(), stableBounds.height());
+        final int otherDimension = Math.max(stableBounds.width(), stableBounds.height());
         final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
         final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
                 : portraitWidth;
@@ -758,7 +786,7 @@
 
         // Get window size based on Nexus 5x screen, we assume that this is enough to show content
         // of activities.
-        final float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+        final float density = (float) displayArea.getConfiguration().densityDpi / DENSITY_DEFAULT;
         final int phonePortraitWidth = (int) (DEFAULT_PORTRAIT_PHONE_WIDTH_DP * density + 0.5f);
         final int phonePortraitHeight = (int) (DEFAULT_PORTRAIT_PHONE_HEIGHT_DP * density + 0.5f);
         final int phoneWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitHeight
@@ -775,83 +803,83 @@
         final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
 
         bounds.set(0, 0, width, height);
-        bounds.offset(displayStableBounds.left, displayStableBounds.top);
+        bounds.offset(stableBounds.left, stableBounds.top);
     }
 
     /**
      * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
-     * centers at its center or display's app bounds center if inOutBounds is empty.
+     * centers at its center or displayArea's app bounds center if inOutBounds is empty.
      */
-    private void centerBounds(@NonNull DisplayContent display, int width, int height,
+    private void centerBounds(@NonNull TaskDisplayArea displayArea, int width, int height,
             @NonNull Rect inOutBounds) {
         if (inOutBounds.isEmpty()) {
-            display.getStableRect(inOutBounds);
+            displayArea.getStableRect(inOutBounds);
         }
         final int left = inOutBounds.centerX() - width / 2;
         final int top = inOutBounds.centerY() - height / 2;
         inOutBounds.set(left, top, left + width, top + height);
     }
 
-    private void adjustBoundsToFitInDisplay(@NonNull DisplayContent display,
+    private void adjustBoundsToFitInDisplayArea(@NonNull TaskDisplayArea displayArea,
             @NonNull Rect inOutBounds) {
-        final Rect displayStableBounds = mTmpStableBounds;
-        display.getStableRect(displayStableBounds);
+        final Rect stableBounds = mTmpStableBounds;
+        displayArea.getStableRect(stableBounds);
 
-        if (displayStableBounds.width() < inOutBounds.width()
-                || displayStableBounds.height() < inOutBounds.height()) {
-            // There is no way for us to fit the bounds in the display without changing width
-            // or height. Just move the start to align with the display.
+        if (stableBounds.width() < inOutBounds.width()
+                || stableBounds.height() < inOutBounds.height()) {
+            // There is no way for us to fit the bounds in the displayArea without changing width
+            // or height. Just move the start to align with the displayArea.
             final int layoutDirection =
                     mSupervisor.mRootWindowContainer.getConfiguration().getLayoutDirection();
             final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL
-                    ? displayStableBounds.right - inOutBounds.right + inOutBounds.left
-                    : displayStableBounds.left;
-            inOutBounds.offsetTo(left, displayStableBounds.top);
+                    ? stableBounds.right - inOutBounds.right + inOutBounds.left
+                    : stableBounds.left;
+            inOutBounds.offsetTo(left, stableBounds.top);
             return;
         }
 
         final int dx;
-        if (inOutBounds.right > displayStableBounds.right) {
-            // Right edge is out of display.
-            dx = displayStableBounds.right - inOutBounds.right;
-        } else if (inOutBounds.left < displayStableBounds.left) {
-            // Left edge is out of display.
-            dx = displayStableBounds.left - inOutBounds.left;
+        if (inOutBounds.right > stableBounds.right) {
+            // Right edge is out of displayArea.
+            dx = stableBounds.right - inOutBounds.right;
+        } else if (inOutBounds.left < stableBounds.left) {
+            // Left edge is out of displayArea.
+            dx = stableBounds.left - inOutBounds.left;
         } else {
-            // Vertical edges are all in display.
+            // Vertical edges are all in displayArea.
             dx = 0;
         }
 
         final int dy;
-        if (inOutBounds.top < displayStableBounds.top) {
-            // Top edge is out of display.
-            dy = displayStableBounds.top - inOutBounds.top;
-        } else if (inOutBounds.bottom > displayStableBounds.bottom) {
-            // Bottom edge is out of display.
-            dy = displayStableBounds.bottom - inOutBounds.bottom;
+        if (inOutBounds.top < stableBounds.top) {
+            // Top edge is out of displayArea.
+            dy = stableBounds.top - inOutBounds.top;
+        } else if (inOutBounds.bottom > stableBounds.bottom) {
+            // Bottom edge is out of displayArea.
+            dy = stableBounds.bottom - inOutBounds.bottom;
         } else {
-            // Horizontal edges are all in display.
+            // Horizontal edges are all in displayArea.
             dy = 0;
         }
         inOutBounds.offset(dx, dy);
     }
 
     /**
-     * Adjusts input bounds to avoid conflict with existing tasks in the display.
+     * Adjusts input bounds to avoid conflict with existing tasks in the displayArea.
      *
      * If the input bounds conflict with existing tasks, this method scans the bounds in a series of
-     * directions to find a location where the we can put the bounds in display without conflict
+     * directions to find a location where the we can put the bounds in displayArea without conflict
      * with any other tasks.
      *
-     * It doesn't try to adjust bounds that's not fully in the given display.
+     * It doesn't try to adjust bounds that's not fully in the given displayArea.
      *
-     * @param display the display which tasks are to check
+     * @param displayArea the displayArea which tasks are to check
      * @param inOutBounds the bounds used to input initial bounds and output result bounds
      */
-    private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
+    private void adjustBoundsToAvoidConflictInDisplayArea(@NonNull TaskDisplayArea displayArea,
             @NonNull Rect inOutBounds) {
         final List<Rect> taskBoundsToCheck = new ArrayList<>();
-        display.forAllRootTasks(task -> {
+        displayArea.forAllRootTasks(task -> {
             if (!task.inFreeformWindowingMode()) {
                 return;
             }
@@ -860,28 +888,28 @@
                 taskBoundsToCheck.add(task.getChildAt(j).getBounds());
             }
         }, false /* traverseTopToBottom */);
-        adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds);
+        adjustBoundsToAvoidConflict(displayArea.getBounds(), taskBoundsToCheck, inOutBounds);
     }
 
     /**
-     * Adjusts input bounds to avoid conflict with provided display bounds and list of tasks bounds
-     * for the display.
+     * Adjusts input bounds to avoid conflict with provided displayArea bounds and list of tasks
+     * bounds for the displayArea.
      *
      * Scans the bounds in directions to find a candidate location that does not conflict with the
-     * provided list of task bounds. If starting bounds are outside the display bounds or if no
+     * provided list of task bounds. If starting bounds are outside the displayArea bounds or if no
      * suitable candidate bounds are found, the method returns the input bounds.
      *
-     * @param displayBounds display bounds used to restrict the candidate bounds
+     * @param displayAreaBounds displayArea bounds used to restrict the candidate bounds
      * @param taskBoundsToCheck list of task bounds to check for conflict
      * @param inOutBounds the bounds used to input initial bounds and output result bounds
      */
     @VisibleForTesting
-    void adjustBoundsToAvoidConflict(@NonNull Rect displayBounds,
+    void adjustBoundsToAvoidConflict(@NonNull Rect displayAreaBounds,
             @NonNull List<Rect> taskBoundsToCheck,
             @NonNull Rect inOutBounds) {
-        if (!displayBounds.contains(inOutBounds)) {
-            // The initial bounds are already out of display. The scanning algorithm below doesn't
-            // work so well with them.
+        if (!displayAreaBounds.contains(inOutBounds)) {
+            // The initial bounds are already out of displayArea. The scanning algorithm below
+            // doesn't work so well with them.
             return;
         }
 
@@ -891,7 +919,7 @@
             return;
         }
 
-        calculateCandidateShiftDirections(displayBounds, inOutBounds);
+        calculateCandidateShiftDirections(displayAreaBounds, inOutBounds);
         for (int direction : mTmpDirections) {
             if (direction == Gravity.NO_GRAVITY) {
                 // We exhausted candidate directions, give up.
@@ -900,12 +928,12 @@
 
             mTmpBounds.set(inOutBounds);
             while (boundsConflict(taskBoundsToCheck, mTmpBounds)
-                    && displayBounds.contains(mTmpBounds)) {
-                shiftBounds(direction, displayBounds, mTmpBounds);
+                    && displayAreaBounds.contains(mTmpBounds)) {
+                shiftBounds(direction, displayAreaBounds, mTmpBounds);
             }
 
             if (!boundsConflict(taskBoundsToCheck, mTmpBounds)
-                    && displayBounds.contains(mTmpBounds)) {
+                    && displayAreaBounds.contains(mTmpBounds)) {
                 // Found a candidate. Just use this.
                 inOutBounds.set(mTmpBounds);
                 if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 1531e56..fc6db61 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -285,18 +285,20 @@
             return false;
         }
 
-        private boolean removeTask(Task t) {
+        private boolean removeTask(Task t, boolean removeFromSystem) {
             mOrganizedTasks.remove(t);
             mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
-
-            if (t.mTaskAppearedSent) {
+            boolean taskAppearedSent = t.mTaskAppearedSent;
+            if (taskAppearedSent) {
                 if (t.getSurfaceControl() != null) {
                     t.migrateToNewSurfaceControl();
                 }
                 t.mTaskAppearedSent = false;
-                return true;
             }
-            return false;
+            if (removeFromSystem) {
+                mService.removeTask(t.mTaskId);
+            }
+            return taskAppearedSent;
         }
 
         void dispose() {
@@ -311,7 +313,7 @@
                 if (mOrganizedTasks.contains(t)) {
                     // updateTaskOrganizerState should remove the task from the list, but still
                     // check it again to avoid while-loop isn't terminate.
-                    if (removeTask(t)) {
+                    if (removeTask(t, t.mRemoveWithTaskOrganizer)) {
                         TaskOrganizerController.this.onTaskVanishedInternal(
                                 mOrganizer.mTaskOrganizer, t);
                     }
@@ -527,7 +529,7 @@
 
     void onTaskVanished(ITaskOrganizer organizer, Task task) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
-        if (state != null && state.removeTask(task)) {
+        if (state != null && state.removeTask(task, false /* removeFromSystem */)) {
             onTaskVanishedInternal(organizer, task);
         }
     }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 98eb11f..ee4c66d 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -135,6 +135,11 @@
         mSyncId = mSyncEngine.startSyncSet(this);
     }
 
+    @VisibleForTesting
+    int getSyncId() {
+        return mSyncId;
+    }
+
     /**
      * Formally starts the transition. Participants can be collected before this is started,
      * but this won't consider itself ready until started -- even if all the participants have
@@ -271,12 +276,17 @@
         // Commit all going-invisible containers
         for (int i = 0; i < mParticipants.size(); ++i) {
             final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
-            if (ar == null || ar.mVisibleRequested) {
-                continue;
+            if (ar != null && !ar.isVisibleRequested()) {
+                ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                        "  Commit activity becoming invisible: %s", ar);
+                ar.commitVisibility(false /* visible */, false /* performLayout */);
             }
-            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
-                    "  Commit activity becoming invisible: %s", ar);
-            ar.commitVisibility(false /* visible */, false /* performLayout */);
+            final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
+            if (wt != null && !wt.isVisibleRequested()) {
+                ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                        "  Commit wallpaper becoming invisible: %s", ar);
+                wt.commitVisibility(false /* visible */);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 1a3138d..7c5afa8 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -126,12 +126,18 @@
         }
 
         mFindResults.resetTopWallpaper = true;
-        if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
-                && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
-
-            // If this window's app token is hidden and not animating, it is of no interest to us.
-            if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
-            return false;
+        if (mService.mAtmService.getTransitionController().getTransitionPlayer() == null) {
+            if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
+                    && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
+                // If this window's app token is hidden and not animating, it is of no interest.
+                if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
+                return false;
+            }
+        } else {
+            if (w.mActivityRecord != null && !w.mActivityRecord.isVisibleRequested()) {
+                // An activity that is not going to remain visible shouldn't be the target.
+                return false;
+            }
         }
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
                 + " mDrawState=" + w.mWinAnimator.mDrawState);
@@ -227,7 +233,10 @@
     }
 
     boolean isWallpaperVisible() {
-        return isWallpaperVisible(mWallpaperTarget);
+        for (int i = mWallpaperTokens.size() - 1; i >= 0; --i) {
+            if (mWallpaperTokens.get(i).isVisible()) return true;
+        }
+        return false;
     }
 
     /**
@@ -240,7 +249,7 @@
         }
     }
 
-    private boolean isWallpaperVisible(WindowState wallpaperTarget) {
+    private boolean shouldWallpaperBeVisible(WindowState wallpaperTarget) {
         if (DEBUG_WALLPAPER) {
             Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + " prev="
                     + mPrevWallpaperTarget);
@@ -255,18 +264,18 @@
     }
 
     void updateWallpaperVisibility() {
-        final boolean visible = isWallpaperVisible(mWallpaperTarget);
+        final boolean visible = shouldWallpaperBeVisible(mWallpaperTarget);
 
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
-            token.updateWallpaperVisibility(visible);
+            token.setVisibility(visible);
         }
     }
 
-    void hideDeferredWallpapersIfNeeded() {
-        if (mDeferredHideWallpaper != null) {
-            hideWallpapers(mDeferredHideWallpaper);
-            mDeferredHideWallpaper = null;
+    void hideDeferredWallpapersIfNeededLegacy() {
+        for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+            final WallpaperWindowToken token = mWallpaperTokens.get(i);
+            token.commitVisibility(false);
         }
     }
 
@@ -275,18 +284,9 @@
                 && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) {
             return;
         }
-        if (mWallpaperTarget != null
-                && mWallpaperTarget.getDisplayContent().mAppTransition.isRunning()) {
-            // Defer hiding the wallpaper when app transition is running until the animations
-            // are done.
-            mDeferredHideWallpaper = winGoingAway;
-            return;
-        }
-
-        final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(i);
-            token.hideWallpaperToken(wasDeferred, "hideWallpapers");
+            token.setVisibility(false);
             if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) {
                 Slog.d(TAG, "Hiding wallpaper " + token
                         + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
@@ -616,7 +616,7 @@
 
         // The window is visible to the compositor...but is it visible to the user?
         // That is what the wallpaper cares about.
-        final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget);
+        final boolean visible = mWallpaperTarget != null;
         if (DEBUG_WALLPAPER) {
             Slog.v(TAG, "Wallpaper visibility: " + visible + " at display "
                     + mDisplayContent.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 43303d4..717775605 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -19,7 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -34,6 +34,8 @@
 import android.view.WindowManager;
 import android.view.animation.Animation;
 
+import com.android.internal.protolog.common.ProtoLog;
+
 import java.util.function.Consumer;
 
 /**
@@ -43,6 +45,8 @@
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM;
 
+    private boolean mVisibleRequested = false;
+
     WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
             DisplayContent dc, boolean ownerCanManageAppTokens) {
         this(service, token, explicit, dc, ownerCanManageAppTokens, null /* options */);
@@ -57,18 +61,16 @@
     }
 
     @Override
+    WallpaperWindowToken asWallpaperToken() {
+        return this;
+    }
+
+    @Override
     void setExiting() {
         super.setExiting();
         mDisplayContent.mWallpaperController.removeWallpaperToken(this);
     }
 
-    void hideWallpaperToken(boolean wasDeferred, String reason) {
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            final WindowState wallpaper = mChildren.get(j);
-            wallpaper.hideWallpaperWindow(wasDeferred, reason);
-        }
-    }
-
     void sendWindowWallpaperCommand(
             String action, int x, int y, int z, Bundle extras, boolean sync) {
         for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
@@ -93,24 +95,6 @@
         }
     }
 
-    void updateWallpaperVisibility(boolean visible) {
-        if (isVisible() != visible) {
-            mWmService.mAtmService.getTransitionController().collect(this);
-            // Need to do a layout to ensure the wallpaper now has the correct size.
-            mDisplayContent.setLayoutNeeded();
-        }
-
-        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
-        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = mChildren.get(wallpaperNdx);
-            if (visible) {
-                wallpaperController.updateWallpaperOffset(wallpaper, false /* sync */);
-            }
-
-            wallpaper.dispatchWallpaperVisibility(visible);
-        }
-    }
-
     /**
      * Starts {@param anim} on all children.
      */
@@ -122,16 +106,16 @@
     }
 
     void updateWallpaperWindows(boolean visible) {
-
         if (isVisible() != visible) {
             if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
                     "Wallpaper token " + token + " visible=" + visible);
-            mWmService.mAtmService.getTransitionController().collect(this);
-            // Need to do a layout to ensure the wallpaper now has the correct size.
-            mDisplayContent.setLayoutNeeded();
+            setVisibility(visible);
+        }
+        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+        if (mWmService.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+            return;
         }
 
-        final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
         final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
 
         if (visible && wallpaperTarget != null) {
@@ -153,21 +137,54 @@
             }
         }
 
-        for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
-            final WindowState wallpaper = mChildren.get(wallpaperNdx);
+        setVisible(visible);
+    }
 
-            if (visible) {
-                wallpaperController.updateWallpaperOffset(wallpaper, false /* sync */);
+    private void setVisible(boolean visible) {
+        final boolean wasClientVisible = isClientVisible();
+        setClientVisible(visible);
+        if (visible && !wasClientVisible) {
+            for (int i = mChildren.size() - 1; i >= 0; i--) {
+                final WindowState wallpaper = mChildren.get(i);
+                wallpaper.requestUpdateWallpaperIfNeeded();
             }
-
-            // First, make sure the client has the current visibility state.
-            wallpaper.dispatchWallpaperVisibility(visible);
-
-            if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
-                    + wallpaper);
         }
     }
 
+    /**
+     * Sets the requested visibility of this token. The visibility may not be if this is part of a
+     * transition. In that situation, make sure to call {@link #commitVisibility} when done.
+     */
+    void setVisibility(boolean visible) {
+        // Before setting mVisibleRequested so we can track changes.
+        mWmService.mAtmService.getTransitionController().collect(this);
+
+        setVisibleRequested(visible);
+
+        // If in a transition, defer commits for activities that are going invisible
+        if (!visible && (mWmService.mAtmService.getTransitionController().inTransition()
+                || getDisplayContent().mAppTransition.isRunning())) {
+            return;
+        }
+
+        commitVisibility(visible);
+    }
+
+    /**
+     * Commits the visibility of this token. This will directly update the visibility without
+     * regard for other state (like being in a transition).
+     */
+    void commitVisibility(boolean visible) {
+        if (visible == isVisible()) return;
+
+        ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS,
+                "commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
+                isVisible(), mVisibleRequested);
+
+        setVisibleRequested(visible);
+        setVisible(visible);
+    }
+
     @Override
     void adjustWindowParams(WindowState win, WindowManager.LayoutParams attrs) {
         if (attrs.height == ViewGroup.LayoutParams.MATCH_PARENT
@@ -186,9 +203,10 @@
     }
 
     boolean hasVisibleNotDrawnWallpaper() {
+        if (!isVisible()) return false;
         for (int j = mChildren.size() - 1; j >= 0; --j) {
             final WindowState wallpaper = mChildren.get(j);
-            if (wallpaper.hasVisibleNotDrawnWallpaper()) {
+            if (!wallpaper.isDrawn() && wallpaper.isVisible()) {
                 return true;
             }
         }
@@ -210,6 +228,21 @@
         return false;
     }
 
+    void setVisibleRequested(boolean visible) {
+        if (mVisibleRequested == visible) return;
+        mVisibleRequested = visible;
+        setInsetsFrozen(!visible);
+    }
+
+    @Override
+    boolean isVisibleRequested() {
+        return mVisibleRequested;
+    }
+
+    @Override
+    boolean isVisible() {
+        return isClientVisible();
+    }
 
     @Override
     public String toString() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dd4ee877..b3d2afb 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -29,6 +29,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.SurfaceControl.Transaction;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
@@ -2684,14 +2685,6 @@
             @Nullable ArrayList<WindowContainer> sources) {
         final Task task = asTask();
         if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
-            if (AppTransition.isClosingTransitOld(transit)) {
-                // Freezes the insets state when the window is in app exiting transition, to
-                // ensure the exiting window won't receive unexpected insets changes from the
-                // next window.
-                task.forAllWindows(w -> {
-                    w.freezeInsetsState();
-                }, true /* traverseTopToBottom */);
-            }
             mDisplayContent.showImeScreenshot();
         }
         final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
@@ -3068,6 +3061,11 @@
     }
 
     /** Cheap way of doing cast and instanceof. */
+    WallpaperWindowToken asWallpaperToken() {
+        return null;
+    }
+
+    /** Cheap way of doing cast and instanceof. */
     DisplayArea asDisplayArea() {
         return null;
     }
@@ -3307,4 +3305,8 @@
         mListeners.remove(listener);
         unregisterConfigurationChangeListener(listener);
     }
+
+    @WindowManager.LayoutParams.WindowType int getWindowType() {
+        return INVALID_WINDOW_TYPE;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index e183ea0..7450782 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -66,7 +66,7 @@
         /**
          * Is trace enabled or not.
          */
-        boolean isEnabled();
+        boolean isAccessibilityTracingEnabled();
 
         /**
          * Add an accessibility trace entry.
@@ -667,4 +667,13 @@
      * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}.
      */
     public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId);
+
+    /**
+     * Checks whether the given window should restore the last IME visibility.
+     *
+     * @param imeTargetWindowToken The token of the (IME target) window
+     * @return {@code true} when the system allows to restore the IME visibility,
+     *         {@code false} otherwise.
+     */
+    public abstract boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c0ccd81..c9e1605 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -39,7 +39,6 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
@@ -224,6 +223,7 @@
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.ICrossWindowBlurEnabledListener;
 import android.view.IDisplayFoldListener;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IDisplayWindowListener;
@@ -757,6 +757,8 @@
 
     final TaskSnapshotController mTaskSnapshotController;
 
+    final BlurController mBlurController = new BlurController();
+
     boolean mIsTouchDevice;
     boolean mIsFakeTouchDevice;
 
@@ -803,8 +805,6 @@
                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT);
         private final Uri mForceResizableUri = Settings.Global.getUriFor(
                 DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
-        private final Uri mSizeCompatFreeformUri = Settings.Global.getUriFor(
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
         private final Uri mSupportsNonResizableMultiWindowUri = Settings.Global.getUriFor(
                 DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW);
         private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
@@ -831,8 +831,6 @@
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mFreeformWindowUri, false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL);
-            resolver.registerContentObserver(mSizeCompatFreeformUri, false, this,
-                    UserHandle.USER_ALL);
             resolver.registerContentObserver(mSupportsNonResizableMultiWindowUri, false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
@@ -872,11 +870,6 @@
                 return;
             }
 
-            if (mSizeCompatFreeformUri.equals(uri)) {
-                updateSizeCompatFreeform();
-                return;
-            }
-
             if (mSupportsNonResizableMultiWindowUri.equals(uri)) {
                 updateSupportsNonResizableMultiWindow();
                 return;
@@ -974,14 +967,6 @@
             mAtmService.mForceResizableActivities = forceResizable;
         }
 
-        void updateSizeCompatFreeform() {
-            ContentResolver resolver = mContext.getContentResolver();
-            final boolean sizeCompatFreeform = Settings.Global.getInt(resolver,
-                    DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
-
-            mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
-        }
-
         void updateSupportsNonResizableMultiWindow() {
             ContentResolver resolver = mContext.getContentResolver();
             final boolean supportsNonResizableMultiWindow = Settings.Global.getInt(resolver,
@@ -3986,6 +3971,21 @@
                     ? backgroundType : LETTERBOX_BACKGROUND_SOLID_COLOR;
     }
 
+    /** Returns a string representing the given {@link LetterboxBackgroundType}. */
+    static String letterboxBackgroundTypeToString(
+            @LetterboxBackgroundType int backgroundType) {
+        switch (backgroundType) {
+            case LETTERBOX_BACKGROUND_SOLID_COLOR:
+                return "LETTERBOX_BACKGROUND_SOLID_COLOR";
+            case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
+                return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND";
+            case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
+                return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING";
+            default:
+                return "unknown=" + backgroundType;
+        }
+    }
+
     @Override
     public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
         if (!checkCallingPermission(
@@ -5690,6 +5690,18 @@
         return mWindowTracing.isEnabled();
     }
 
+    @Override
+    public boolean registerCrossWindowBlurEnabledListener(
+                ICrossWindowBlurEnabledListener listener) {
+        return mBlurController.registerCrossWindowBlurEnabledListener(listener);
+    }
+
+    @Override
+    public void unregisterCrossWindowBlurEnabledListener(
+                ICrossWindowBlurEnabledListener listener) {
+        mBlurController.unregisterCrossWindowBlurEnabledListener(listener);
+    }
+
     // -------------------------------------------------------------
     // Internals
     // -------------------------------------------------------------
@@ -6429,6 +6441,7 @@
             }
         });
         pw.print("  mInTouchMode="); pw.println(mInTouchMode);
+        pw.print("  mBlurEnabled="); pw.println(mBlurController.mBlurEnabled);
         pw.print("  mLastDisplayFreezeDuration=");
                 TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
                 if ( mLastFinishedFreezeSource != null) {
@@ -8026,6 +8039,11 @@
                 return dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getName();
             }
         }
+
+        @Override
+        public boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
+            return WindowManagerService.this.shouldRestoreImeVisibility(imeTargetWindowToken);
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
@@ -8683,6 +8701,22 @@
                 boundsInWindow, hashAlgorithm, callback);
     }
 
+    boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
+        synchronized (mGlobalLock) {
+            final WindowState imeTargetWindow = mWindowMap.get(imeTargetWindowToken);
+            if (imeTargetWindow == null) {
+                return false;
+            }
+            final Task imeTargetWindowTask = imeTargetWindow.getTask();
+            if (imeTargetWindowTask == null) {
+                return false;
+            }
+            final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId,
+                    false /* isLowResolution */);
+            return snapshot != null && snapshot.hasImeSurface();
+        }
+    }
+
     private void sendDisplayHashError(RemoteCallback callback, int errorCode) {
         Bundle bundle = new Bundle();
         bundle.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1fc7041..0a4451f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -141,11 +141,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
@@ -358,7 +356,6 @@
     private boolean mForceHideNonSystemOverlayWindow;
     boolean mAppFreezing;
     boolean mHidden = true;    // Used to determine if to show child windows.
-    boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
     private boolean mDragResizing;
     private boolean mDragResizingChangeReported = true;
     private int mResizeMode;
@@ -797,7 +794,7 @@
      * {@link InsetsStateController#notifyInsetsChanged}.
      */
     boolean isReadyToDispatchInsetsState() {
-        return isVisible() && mFrozenInsetsState == null;
+        return isVisibleRequested() && mFrozenInsetsState == null;
     }
 
     void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation,
@@ -1190,16 +1187,6 @@
             layoutYDiff = 0;
         } else {
             windowFrames.mContainingFrame.set(getBounds());
-            if (mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) {
-
-                // If the bounds are frozen, we still want to translate the window freely and only
-                // freeze the size.
-                Rect frozen = mActivityRecord.mFrozenBounds.peek();
-                windowFrames.mContainingFrame.right =
-                        windowFrames.mContainingFrame.left + frozen.width();
-                windowFrames.mContainingFrame.bottom =
-                        windowFrames.mContainingFrame.top + frozen.height();
-            }
             // IME is up and obscuring this window. Adjust the window position so it is visible.
             if (isImeTarget) {
                 if (inFreeformWindowingMode()) {
@@ -1725,7 +1712,11 @@
 
     @Override
     boolean isVisibleRequested() {
-        return isVisible() && (mActivityRecord == null || mActivityRecord.isVisibleRequested());
+        if (mToken != null && (mActivityRecord != null || mToken.asWallpaperToken() != null)) {
+            // Currently only ActivityRecord and WallpaperToken support visibleRequested.
+            return isVisible() && mToken.isVisibleRequested();
+        }
+        return isVisible();
     }
 
     /**
@@ -1755,8 +1746,11 @@
      *         {@code false} otherwise.
      */
     boolean wouldBeVisibleIfPolicyIgnored() {
-        return mHasSurface && !isParentWindowHidden()
-                && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
+        if (!mHasSurface || isParentWindowHidden() || mAnimatingExit || mDestroying) {
+            return false;
+        }
+        final boolean isWallpaper = mToken != null && mToken.asWallpaperToken() != null;
+        return !isWallpaper || mToken.isVisible();
     }
 
     /**
@@ -1814,6 +1808,10 @@
             return ((!isParentWindowHidden() && atoken.isVisible())
                     || isAnimating(TRANSITION | PARENTS));
         }
+        final WallpaperWindowToken wtoken = mToken.asWallpaperToken();
+        if (wtoken != null) {
+            return !isParentWindowHidden() && wtoken.isVisible();
+        }
         return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS);
     }
 
@@ -1953,8 +1951,9 @@
         // When there is keyguard, wallpaper could be placed over the secure app
         // window but invisible. We need to check wallpaper visibility explicitly
         // to determine if it's occluding apps.
-        return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
-                || (mIsWallpaper && mWallpaperVisible))
+        final boolean isWallpaper = mToken != null && mToken.asWallpaperToken() != null;
+        return ((!isWallpaper && mAttrs.format == PixelFormat.OPAQUE)
+                || (isWallpaper && mToken.isVisible()))
                 && isDrawn() && !isAnimating(TRANSITION | PARENTS);
     }
 
@@ -2068,23 +2067,6 @@
         super.onResize();
     }
 
-    void onUnfreezeBounds() {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowState c = mChildren.get(i);
-            c.onUnfreezeBounds();
-        }
-
-        if (!mHasSurface) {
-            return;
-        }
-
-        mLayoutNeeded = true;
-        setDisplayLayoutNeeded();
-        if (!mWmService.mResizingWindows.contains(this)) {
-            mWmService.mResizingWindows.add(this);
-        }
-    }
-
     /**
      * If the window has moved due to its containing content frame changing, then notify the
      * listeners and optionally animate it. Simply checking a change of position is not enough,
@@ -3251,7 +3233,11 @@
     void sendAppVisibilityToClients() {
         super.sendAppVisibilityToClients();
 
-        final boolean clientVisible = mActivityRecord.isClientVisible();
+        if (mToken == null) return;
+
+        final boolean clientVisible = mToken.isClientVisible();
+        // TODO(shell-transitions): This is currently only applicable to app windows, BUT we
+        //                          want to extend the "starting" concept to other windows.
         if (mAttrs.type == TYPE_APPLICATION_STARTING && !clientVisible) {
             // Don't hide the starting window.
             return;
@@ -3579,10 +3565,6 @@
 
     @Override
     public Configuration getConfiguration() {
-        if (mActivityRecord != null && mActivityRecord.mFrozenMergedConfig.size() > 0) {
-            return mActivityRecord.mFrozenMergedConfig.peek();
-        }
-
         // If the process has not registered to any display area to listen to the configuration
         // change, we can simply return the mFullConfiguration as default.
         if (!registeredForDisplayAreaConfigChanges()) {
@@ -3639,9 +3621,11 @@
         if (mActivityRecord != null && mActivityRecord.isRelaunching()) {
             return;
         }
-        // If the activity is invisible or going invisible, don't report either since it is going
-        // away. This is likely during a transition so we want to preserve the original state.
-        if (mActivityRecord != null && !mActivityRecord.isVisibleRequested()) {
+        // If this is an activity or wallpaper and is invisible or going invisible, don't report
+        // either since it is going away. This is likely during a transition so we want to preserve
+        // the original state.
+        if ((mActivityRecord != null || mToken.asWallpaperToken() != null)
+                && !mToken.isVisibleRequested()) {
             return;
         }
 
@@ -3944,14 +3928,8 @@
             return true;
         }
 
-        // If the bounds are currently frozen, it means that the layout size that the app sees
-        // and the bounds we clip this window to might be different. In order to avoid holes, we
-        // simulate that we are still resizing so the app fills the hole with the resizing
-        // background.
-        return (getDisplayContent().mDividerControllerLocked.isResizing()
-                        || mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
-                !task.inFreeformWindowingMode() && !isGoneForLayout();
-
+        return getDisplayContent().mDividerControllerLocked.isResizing()
+                && !task.inFreeformWindowingMode() && !isGoneForLayout();
     }
 
     void setDragResizing() {
@@ -4061,8 +4039,7 @@
         if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
             pw.println(prefix + "mIsImWindow=" + mIsImWindow
                     + " mIsWallpaper=" + mIsWallpaper
-                    + " mIsFloatingLayer=" + mIsFloatingLayer
-                    + " mWallpaperVisible=" + mWallpaperVisible);
+                    + " mIsFloatingLayer=" + mIsFloatingLayer);
         }
         if (dumpAll) {
             pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
@@ -4876,61 +4853,6 @@
         return getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
     }
 
-    void hideWallpaperWindow(boolean wasDeferred, String reason) {
-        for (int j = mChildren.size() - 1; j >= 0; --j) {
-            final WindowState c = mChildren.get(j);
-            c.hideWallpaperWindow(wasDeferred, reason);
-        }
-        if (!mWinAnimator.mLastHidden || wasDeferred) {
-            mWinAnimator.hide(getGlobalTransaction(), reason);
-            getDisplayContent().mWallpaperController.mDeferredHideWallpaper = null;
-            dispatchWallpaperVisibility(false);
-            final DisplayContent displayContent = getDisplayContent();
-            if (displayContent != null) {
-                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                if (DEBUG_LAYOUT_REPEATS) {
-                    mWmService.mWindowPlacerLocked.debugLayoutRepeats("hideWallpaperWindow " + this,
-                            displayContent.pendingLayoutChanges);
-                }
-            }
-        }
-    }
-
-    /**
-     * Check wallpaper window for visibility change and notify window if so.
-     * @param visible Current visibility.
-     */
-    void dispatchWallpaperVisibility(final boolean visible) {
-        final boolean hideAllowed =
-                getDisplayContent().mWallpaperController.mDeferredHideWallpaper == null;
-
-        // Only send notification if the visibility actually changed and we are not trying to hide
-        // the wallpaper when we are deferring hiding of the wallpaper.
-        if (mWallpaperVisible != visible && (hideAllowed || visible)) {
-            mWallpaperVisible = visible;
-            try {
-                if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
-                        "Updating vis of wallpaper " + this
-                                + ": " + visible + " from:\n" + Debug.getCallers(4, "  "));
-                mClient.dispatchAppVisibility(visible);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    boolean hasVisibleNotDrawnWallpaper() {
-        if (mWallpaperVisible && !isDrawn()) {
-            return true;
-        }
-        for (int j = mChildren.size() - 1; j >= 0; --j) {
-            final WindowState c = mChildren.get(j);
-            if (c.hasVisibleNotDrawnWallpaper()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     void updateReportedVisibility(UpdateReportedVisibilityResults results) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowState c = mChildren.get(i);
@@ -5273,22 +5195,24 @@
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
             getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
-        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || (mAttrs.flags & FLAG_BLUR_BEHIND) != 0)
+        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
                    && isVisibleNow() && !mHidden) {
             // Only show the Dimmer when the following is satisfied:
-            // 1. The window has the flag FLAG_DIM_BEHIND or background blur is requested
+            // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
             // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
             // 3. The WS is considered visible according to the isVisible() method
             // 4. The WS is not hidden.
             mIsDimming = true;
             final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
-            final int blurRadius =
-                    (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 ? mAttrs.blurBehindRadius : 0;
-            getDimmer().dimBelow(
-                    getSyncTransaction(), this, mAttrs.dimAmount, mAttrs.blurBehindRadius);
+            final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
+            getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount, blurRadius);
         }
     }
 
+    private boolean shouldDrawBlurBehind() {
+        return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mWmService.mBlurController.mBlurEnabled;
+    }
+
     /**
      * Notifies SF about the priority of the window, if it changed. SF then uses this information
      * to decide which window's desired rendering rate should have a priority when deciding about
@@ -5853,4 +5777,9 @@
         outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top,
                 -attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom);
     }
+
+    @Override
+    @WindowManager.LayoutParams.WindowType int getWindowType() {
+        return mAttrs.type;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ece256e..ebbebbb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -57,7 +57,6 @@
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.os.Debug;
 import android.os.Trace;
 import android.util.Slog;
@@ -575,10 +574,7 @@
 
         setSurfaceBoundariesLocked(t);
 
-        if (mIsWallpaper && !w.mWallpaperVisible) {
-            // Wallpaper is no longer visible and there is no wp target => hide it.
-            hide(t, "prepareSurfaceLocked");
-        } else if (w.isParentWindowHidden() || !w.isOnScreen()) {
+        if (w.isParentWindowHidden() || !w.isOnScreen()) {
             hide(t, "prepareSurfaceLocked");
             mWallpaperControllerLocked.hideWallpapers(w);
 
@@ -631,9 +627,6 @@
                     if (showSurfaceRobustlyLocked(t)) {
                         mAnimator.requestRemovalOfReplacedWindows(w);
                         mLastHidden = false;
-                        if (mIsWallpaper) {
-                            w.dispatchWallpaperVisibility(true);
-                        }
                         final DisplayContent displayContent = w.getDisplayContent();
                         if (!displayContent.getLastHasContent()) {
                             // This draw means the difference between unique content and mirroring.
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e87ee91..5276d9c8 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -112,6 +113,9 @@
      */
     private final boolean mFromClientToken;
 
+    /** Have we told the window clients to show themselves? */
+    private boolean mClientVisible;
+
     /**
      * Used to fix the transform of the token to be rotated to a rotation different than it's
      * display. The window frames and surfaces corresponding to this token will be layouted and
@@ -397,6 +401,21 @@
         return builder;
     }
 
+    boolean isClientVisible() {
+        return mClientVisible;
+    }
+
+    void setClientVisible(boolean clientVisible) {
+        if (mClientVisible == clientVisible) {
+            return;
+        }
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible,
+                Debug.getCallers(5));
+        mClientVisible = clientVisible;
+        sendAppVisibilityToClients();
+    }
+
     boolean hasFixedRotationTransform() {
         return mFixedRotationTransformState != null;
     }
@@ -736,4 +755,18 @@
     boolean isFromClient() {
         return mFromClientToken;
     }
+
+    /** @see WindowState#freezeInsetsState() */
+    void setInsetsFrozen(boolean freeze) {
+        if (freeze) {
+            forAllWindows(WindowState::freezeInsetsState, true /* traverseTopToBottom */);
+        } else {
+            forAllWindows(WindowState::clearFrozenInsetsState, true /* traverseTopToBottom */);
+        }
+    }
+
+    @Override
+    @WindowManager.LayoutParams.WindowType int getWindowType() {
+        return windowType;
+    }
 }
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index c285ef5..6a8f6d4 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -30,7 +30,6 @@
     gen_writer: true,
 }
 
-
 xsd_config {
     name: "display-device-config",
     srcs: ["display-device-config/display-device-config.xsd"],
@@ -38,6 +37,12 @@
     package_name: "com.android.server.display.config",
 }
 
+xsd_config {
+    name: "display-layout-config",
+    srcs: ["display-layout-config/display-layout-config.xsd"],
+    api_dir: "display-layout-config/schema",
+    package_name: "com.android.server.display.config.layout",
+}
 
 xsd_config {
     name: "cec-config",
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 7d705c1..e4b9612 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -1,23 +1,24 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  ~ Copyright (C) 2020 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.
-  -->
+    Copyright (C) 2020 The Android Open Source Project
 
-<!-- This defines the format of the XML file generated by
-  ~ com.android.compat.annotation.ChangeIdProcessor annotation processor (from
-  ~ tools/platform-compat), and is parsed in com/android/server/compat/CompatConfig.java.
+    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.
+-->
+
+<!--
+    This defines the format of the XML file used to provide static configuration values
+    for the displays on a device.
+    It is parsed in com/android/server/display/DisplayDeviceConfig.java
 -->
 <xs:schema version="2.0"
            elementFormDefault="qualified"
diff --git a/services/core/xsd/display-layout-config/OWNERS b/services/core/xsd/display-layout-config/OWNERS
new file mode 100644
index 0000000..20b75be
--- /dev/null
+++ b/services/core/xsd/display-layout-config/OWNERS
@@ -0,0 +1,3 @@
+include /services/core/java/com/android/server/display/OWNERS
+
+flc@google.com
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
new file mode 100644
index 0000000..c542c0d
--- /dev/null
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (C) 2021 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.
+-->
+
+<!--
+    This defines the format of the XML file used to defines how displays are laid out
+    for a given device-state.
+    It is parsed in com/android/server/display/layout/DeviceStateToLayoutMap.java
+    More information on device-state can be found in DeviceStateManager.java
+-->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="layouts">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element type="layout" name="layout" minOccurs="1" maxOccurs="unbounded" />
+            </xs:sequence>
+        </xs:complexType>
+
+        <!-- Ensures only one layout is allowed per device state. -->
+        <xs:unique name="UniqueState">
+            <xs:selector xpath="layout" />
+            <xs:field xpath="@state" />
+        </xs:unique>
+    </xs:element>
+
+    <!-- Type definitions -->
+
+    <xs:complexType name="layout">
+        <xs:sequence>
+            <xs:element name="state" type="xs:nonNegativeInteger" />
+            <xs:element name="display" type="display" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="display">
+        <xs:sequence>
+            <xs:element name="address" type="xs:nonNegativeInteger"/>
+        </xs:sequence>
+        <xs:attribute name="enabled" type="xs:boolean" use="optional" />
+        <xs:attribute name="isDefault" type="xs:boolean" use="optional" />
+    </xs:complexType>
+</xs:schema>
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
new file mode 100644
index 0000000..8171885
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -0,0 +1,34 @@
+// Signature format: 2.0
+package com.android.server.display.config.layout {
+
+  public class Display {
+    ctor public Display();
+    method public java.math.BigInteger getAddress();
+    method public boolean getEnabled();
+    method public boolean getIsDefault();
+    method public void setAddress(java.math.BigInteger);
+    method public void setEnabled(boolean);
+    method public void setIsDefault(boolean);
+  }
+
+  public class Layout {
+    ctor public Layout();
+    method public java.util.List<com.android.server.display.config.layout.Display> getDisplay();
+    method public java.math.BigInteger getState();
+    method public void setState(java.math.BigInteger);
+  }
+
+  public class Layouts {
+    ctor public Layouts();
+    method public java.util.List<com.android.server.display.config.layout.Layout> getLayout();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static com.android.server.display.config.layout.Layouts read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/services/core/xsd/display-layout-config/schema/last_current.txt b/services/core/xsd/display-layout-config/schema/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/last_current.txt
diff --git a/services/core/xsd/display-layout-config/schema/last_removed.txt b/services/core/xsd/display-layout-config/schema/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/last_removed.txt
diff --git a/services/core/xsd/display-layout-config/schema/removed.txt b/services/core/xsd/display-layout-config/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 524892b..04af5c9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -715,6 +715,9 @@
     @Nullable
     private DevicePolicySafetyChecker mSafetyChecker;
 
+    @GuardedBy("getLockObject()")
+    private final ArrayList<Object> mPendingUserCreatedCallbackTokens = new ArrayList<>();
+
     public static final class Lifecycle extends SystemService {
         private BaseIDevicePolicyManager mService;
 
@@ -753,21 +756,25 @@
 
         @Override
         public void onUserStarting(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleStartUser(user.getUserIdentifier());
         }
 
         @Override
         public void onUserUnlocking(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleUnlockUser(user.getUserIdentifier());
         }
 
         @Override
         public void onUserStopping(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleStopUser(user.getUserIdentifier());
         }
 
         @Override
         public void onUserUnlocked(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleOnUserUnlocked(user.getUserIdentifier());
         }
     }
@@ -965,8 +972,8 @@
     private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
 
         @Override
-        public void onUserCreated(UserInfo user) {
-            mHandler.post(() -> handleNewUserCreated(user));
+        public void onUserCreated(UserInfo user, Object token) {
+            mHandler.post(() -> handleNewUserCreated(user, token));
         }
     }
 
@@ -1576,8 +1583,7 @@
         }
 
         public String[] getPersonalAppsForSuspension(int userId) {
-            return new PersonalAppsSuspensionHelper(
-                    mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */))
+            return PersonalAppsSuspensionHelper.forUser(mContext, userId)
                     .getPersonalAppsForSuspension();
         }
 
@@ -1592,6 +1598,10 @@
         void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
             mSafetyChecker = safetyChecker;
         }
+
+        void dumpPerUserData(IndentingPrintWriter pw, @UserIdInt int userId) {
+            PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw);
+        }
     }
 
     /**
@@ -3151,11 +3161,6 @@
         if (!mHasFeature) {
             return;
         }
-        setActiveAdmin(adminReceiver, refreshing, userHandle, null);
-    }
-
-    private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
-            Bundle onEnableData) {
         Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
 
         final CallerIdentity caller = getCallerIdentity();
@@ -3198,7 +3203,7 @@
                 }
                 saveSettingsLocked(userHandle);
                 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
-                        onEnableData, null);
+                        /* adminExtras= */ null, /* result= */ null);
             });
         }
     }
@@ -9159,11 +9164,17 @@
         }
     }
 
-    private void dumpDevicePolicyData(IndentingPrintWriter pw) {
+    private void dumpPerUserData(IndentingPrintWriter pw) {
         int userCount = mUserData.size();
-        for (int u = 0; u < userCount; u++) {
-            DevicePolicyData policy = getUserData(mUserData.keyAt(u));
+        for (int userId = 0; userId < userCount; userId++) {
+            DevicePolicyData policy = getUserData(mUserData.keyAt(userId));
             policy.dump(pw);
+            pw.println();
+
+            pw.increaseIndent();
+            mInjector.dumpPerUserData(pw, userId);
+            pw.decreaseIndent();
+            pw.println();
         }
     }
 
@@ -9181,19 +9192,30 @@
                 pw.println();
                 mDeviceAdminServiceController.dump(pw);
                 pw.println();
-                dumpDevicePolicyData(pw);
+                dumpPerUserData(pw);
                 pw.println();
                 mConstants.dump(pw);
                 pw.println();
                 mStatLogger.dump(pw);
                 pw.println();
-
                 pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
                 pw.println();
+
+                if (mPendingUserCreatedCallbackTokens.isEmpty()) {
+                    pw.println("no pending user created callback tokens");
+                } else {
+                    int size = mPendingUserCreatedCallbackTokens.size();
+                    pw.printf("%d pending user created callback token%s\n", size,
+                            (size == 1 ? "" : "s"));
+                }
+                pw.println();
+
                 mPolicyCache.dump(pw);
                 pw.println();
                 mStateCache.dump(pw);
+                pw.println();
             }
+            dumpResources(pw);
         }
     }
 
@@ -9208,6 +9230,42 @@
         pw.decreaseIndent();
     }
 
+    private void dumpResources(IndentingPrintWriter pw) {
+        mOverlayPackagesProvider.dump(pw);
+        pw.println();
+
+        pw.println("Other overlayable app resources");
+        pw.increaseIndent();
+        dumpResources(pw, mContext, "cross_profile_apps", R.array.cross_profile_apps);
+        dumpResources(pw, mContext, "vendor_cross_profile_apps", R.array.vendor_cross_profile_apps);
+        dumpResources(pw, mContext, "config_packagesExemptFromSuspension",
+                R.array.config_packagesExemptFromSuspension);
+        pw.decreaseIndent();
+        pw.println();
+    }
+
+    static void dumpResources(IndentingPrintWriter pw, Context context, String resName, int resId) {
+        dumpApps(pw, resName, context.getResources().getStringArray(resId));
+    }
+
+    static void dumpApps(IndentingPrintWriter pw, String name, String[] apps) {
+        dumpApps(pw, name, Arrays.asList(apps));
+    }
+
+    static void dumpApps(IndentingPrintWriter pw, String name, List apps) {
+        if (apps == null || apps.isEmpty()) {
+            pw.printf("%s: empty\n", name);
+            return;
+        }
+        int size = apps.size();
+        pw.printf("%s: %d app%s\n", name, size, size == 1 ? "" : "s");
+        pw.increaseIndent();
+        for (int i = 0; i < size; i++) {
+            pw.printf("%d: %s\n", i, apps.get(i));
+        }
+        pw.decreaseIndent();
+    }
+
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
@@ -9946,8 +10004,8 @@
                 clearInitBundle = sendAdminCommandLocked(admin,
                         DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
                         initBundle == null ? null : new Bundle(initBundle),
-                        null /* result receiver */,
-                        true /* send in foreground */);
+                        /* result= */ null ,
+                        /* inForeground= */ true);
             }
             if (clearInitBundle) {
                 // If there's no admin or we've successfully called the admin, clear the init bundle
@@ -10020,9 +10078,13 @@
                             UserHandle.myUserId(), ACTION_PROVISION_MANAGED_USER).toArray(
                             new String[0]);
                 }
+
+                Object token = new Object();
+                Slog.d(LOG_TAG, "Adding new pending token: " + token);
+                mPendingUserCreatedCallbackTokens.add(token);
                 try {
                     UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
-                            userType, userInfoFlags, disallowedPackages);
+                            userType, userInfoFlags, disallowedPackages, token);
                     if (userInfo != null) {
                         user = userInfo.getUserHandle();
                     }
@@ -10032,7 +10094,8 @@
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
-        }
+        } // synchronized
+
         if (user == null) {
             if (targetSdkVersion >= Build.VERSION_CODES.P) {
                 throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN,
@@ -10054,14 +10117,8 @@
 
         final long id = mInjector.binderClearCallingIdentity();
         try {
-            if (!mInjector.userManagerIsHeadlessSystemUserMode()) {
-                manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
-                        /* showDisclaimer= */ true);
-            } else if (VERBOSE_LOG) {
-                Slog.v(LOG_TAG, "createAndManageUser(): skipping manageUserUnchecked() on user "
-                        + userHandle + " on headless system user as it will be called by "
-                                + "handleNewUserCreated()");
-            }
+            manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
+                    /* showDisclaimer= */ true);
 
             if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -10083,7 +10140,15 @@
     }
 
     private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner,
-            @UserIdInt int userId, PersistableBundle adminExtras, boolean showDisclaimer) {
+            @UserIdInt int userId, @Nullable PersistableBundle adminExtras,
+            boolean showDisclaimer) {
+        synchronized (getLockObject()) {
+            if (VERBOSE_LOG) {
+                Slog.v(LOG_TAG, "manageUserUnchecked(): admin=" + admin + ", po=" + profileOwner
+                        + ", userId=" + userId + ", hasAdminExtras=" + (adminExtras != null)
+                        + ", showDisclaimer=" + showDisclaimer);
+            }
+        }
         final String adminPkg = admin.getPackageName();
         try {
             // Install the profile owner if not present.
@@ -10113,23 +10178,37 @@
                     ? DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED
                     : DevicePolicyData.NEW_USER_DISCLAIMER_NOT_NEEDED;
             saveSettingsLocked(userId);
+
         }
     }
 
-    private void handleNewUserCreated(UserInfo user) {
-        if (VERBOSE_LOG) Slog.v(LOG_TAG, "handleNewUserCreated(): " + user.toFullString());
-
-        if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return;
+    private void handleNewUserCreated(UserInfo user, @Nullable Object token) {
+        if (VERBOSE_LOG) {
+            Slog.v(LOG_TAG, "handleNewUserCreated(): user=" + user.toFullString()
+                    + ", token=" + token);
+        }
 
         final int userId = user.id;
+        if (token != null) {
+            synchronized (getLockObject()) {
+                if (mPendingUserCreatedCallbackTokens.contains(token)) {
+                    // Ignore because it was triggered by createAndManageUser()
+                    Slog.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId
+                            + " due to token" + token);
+                    mPendingUserCreatedCallbackTokens.remove(token);
+                    return;
+                }
+            }
+        }
+
+        if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return;
 
         if (mInjector.userManagerIsHeadlessSystemUserMode()) {
             ComponentName admin = mOwners.getDeviceOwnerComponent();
             Slog.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user "
                     + userId);
             manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
-                    /* managedUser= */ userId, /* adminExtras= */ null,
-                    /* showDisclaimer= */ true);
+                    /* managedUser= */ userId, /* adminExtras= */ null, /* showDisclaimer= */ true);
         } else {
             Log.i(LOG_TAG, "User " + userId + " added on DO mode; setting ShowNewUserDisclaimer");
             setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED);
@@ -10250,11 +10329,12 @@
         final long id = mInjector.binderClearCallingIdentity();
         try {
             if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
-                Log.w(LOG_TAG, "Cannot start more users in background");
+                Log.w(LOG_TAG, "Cannot start user " + userId + ", too many users in background");
                 return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
             }
 
             if (mInjector.getIActivityManager().startUserInBackground(userId)) {
+                Log.i(LOG_TAG, "Started used " + userId + " in background");
                 return UserManager.USER_OPERATION_SUCCESS;
             } else {
                 return UserManager.USER_OPERATION_ERROR_UNKNOWN;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
index 261a83c..280f12f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
@@ -21,6 +21,7 @@
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
@@ -32,6 +33,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
 import android.view.inputmethod.InputMethodInfo;
 
 import com.android.internal.R;
@@ -224,4 +226,39 @@
         }
         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
     }
+
+    void dump(IndentingPrintWriter pw) {
+        pw.println("OverlayPackagesProvider");
+        pw.increaseIndent();
+
+        dumpResources(pw, mContext, "required_apps_managed_device",
+                R.array.required_apps_managed_device);
+        dumpResources(pw, mContext, "required_apps_managed_user",
+                R.array.required_apps_managed_user);
+        dumpResources(pw, mContext, "required_apps_managed_profile",
+                R.array.required_apps_managed_profile);
+
+        dumpResources(pw, mContext, "disallowed_apps_managed_device",
+                R.array.disallowed_apps_managed_device);
+        dumpResources(pw, mContext, "disallowed_apps_managed_user",
+                R.array.disallowed_apps_managed_user);
+        dumpResources(pw, mContext, "disallowed_apps_managed_device",
+                R.array.disallowed_apps_managed_device);
+
+        dumpResources(pw, mContext, "vendor_required_apps_managed_device",
+                R.array.vendor_required_apps_managed_device);
+        dumpResources(pw, mContext, "vendor_required_apps_managed_user",
+                R.array.vendor_required_apps_managed_user);
+        dumpResources(pw, mContext, "vendor_required_apps_managed_profile",
+                R.array.vendor_required_apps_managed_profile);
+
+        dumpResources(pw, mContext, "vendor_disallowed_apps_managed_user",
+                R.array.vendor_disallowed_apps_managed_user);
+        dumpResources(pw, mContext, "vendor_disallowed_apps_managed_device",
+                R.array.vendor_disallowed_apps_managed_device);
+        dumpResources(pw, mContext, "vendor_disallowed_apps_managed_profile",
+                R.array.vendor_disallowed_apps_managed_profile);
+
+        pw.decreaseIndent();
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index c6871842..37dbfc1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -20,6 +20,7 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -29,10 +30,12 @@
 import android.content.pm.ResolveInfo;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
@@ -49,7 +52,7 @@
 /**
  * Utility class to find what personal apps should be suspended to limit personal device use.
  */
-public class PersonalAppsSuspensionHelper {
+public final class PersonalAppsSuspensionHelper {
     private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
 
     // Flags to get all packages even if the user is still locked.
@@ -60,9 +63,17 @@
     private final PackageManager mPackageManager;
 
     /**
+     * Factory method
+     */
+    public static PersonalAppsSuspensionHelper forUser(Context context, @UserIdInt int userId) {
+        return new PersonalAppsSuspensionHelper(context.createContextAsUser(UserHandle.of(userId),
+                /* flags= */ 0));
+    }
+
+    /**
      * @param context Context for the user whose apps should to be suspended.
      */
-    public PersonalAppsSuspensionHelper(Context context) {
+    private PersonalAppsSuspensionHelper(Context context) {
         mContext = context;
         mPackageManager = context.getPackageManager();
     }
@@ -181,4 +192,21 @@
                 iBinder == null ? null : IAccessibilityManager.Stub.asInterface(iBinder);
         return new AccessibilityManager(mContext, service, userId);
     }
+
+    void dump(IndentingPrintWriter pw) {
+        pw.println("PersonalAppsSuspensionHelper");
+        pw.increaseIndent();
+
+        DevicePolicyManagerService.dumpApps(pw, "critical packages", getCriticalPackages());
+        DevicePolicyManagerService.dumpApps(pw, "launcher packages", getSystemLauncherPackages());
+        DevicePolicyManagerService.dumpApps(pw, "accessibility services",
+                getAccessibilityServices());
+        DevicePolicyManagerService.dumpApps(pw, "input method packages", getInputMethodPackages());
+        pw.printf("SMS package: %s\n", Telephony.Sms.getDefaultSmsPackage(mContext));
+        pw.printf("Settings package: %s\n", getSettingsPackageName());
+        DevicePolicyManagerService.dumpApps(pw, "Packages subject to suspension",
+                getPersonalAppsForSuspension());
+
+        pw.decreaseIndent();
+    }
 }
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 0d878b4..a262939 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -102,7 +102,7 @@
             return false;
         }
         try {
-            return !mIProfcollect.GetSupportedProvider().isEmpty();
+            return !mIProfcollect.get_supported_provider().isEmpty();
         } catch (RemoteException e) {
             Log.e(LOG_TAG, e.getMessage());
             return false;
@@ -191,7 +191,7 @@
             }
 
             try {
-                sSelfService.mIProfcollect.ProcessProfile();
+                sSelfService.mIProfcollect.process(false);
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, e.getMessage());
             }
@@ -234,7 +234,7 @@
                 if (DEBUG) {
                     Log.d(LOG_TAG, "Tracing on app launch event: " + packageName);
                 }
-                mIProfcollect.TraceOnce("applaunch");
+                mIProfcollect.trace_once("applaunch");
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, e.getMessage());
             }
@@ -296,7 +296,7 @@
         }
 
         try {
-            mIProfcollect.CreateProfileReport();
+            mIProfcollect.report();
         } catch (RemoteException e) {
             Log.e(LOG_TAG, e.getMessage());
         }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index e99b071..0fa9a1d 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -52,8 +52,10 @@
         val collector = mockCollector()
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg))
+        assertThat(collector.collectValidAutoVerifyDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com", "example4.com")
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+                .containsExactly("invalid1", "invalid2", "invalid3", "invalid4")
     }
 
     @Test
@@ -62,7 +64,8 @@
         val collector = mockCollector()
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     @Test
@@ -71,8 +74,10 @@
         val collector = mockCollector(linkedApps = setOf(TEST_PKG_NAME))
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg))
+        assertThat(collector.collectValidAutoVerifyDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com", "example4.com")
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+                .containsExactly("invalid1", "invalid2", "invalid3", "invalid4")
     }
 
     @Test
@@ -92,6 +97,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example1.com", null)
+                                    addDataAuthority("invalid1", null)
                                 }
                         )
                     },
@@ -111,6 +117,7 @@
                                     addDataScheme("nonWebScheme")
                                     addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example2.com", null)
+                                    addDataAuthority("invalid2", null)
                                 }
                         )
                     },
@@ -122,7 +129,8 @@
         val collector = mockCollector()
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     @Test
@@ -132,8 +140,10 @@
 
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg))
+        assertThat(collector.collectValidAutoVerifyDomains(pkg))
                 .containsExactly("example1.com", "example3.com")
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+                .containsExactly("invalid1", "invalid3")
     }
 
     @Test
@@ -143,7 +153,8 @@
 
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     @Test
@@ -153,7 +164,8 @@
 
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     private fun mockCollector(linkedApps: Set<String> = emptySet()): DomainVerificationCollector {
@@ -178,6 +190,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub"/>
                     <data android:host="example1.com"/>
+                    <data android:host="invalid1"/>
                 </intent-filter>
                 <intent-filter>
                     <action android:name="android.intent.action.VIEW"/>
@@ -186,6 +199,7 @@
                     <data android:scheme="http"/>
                     <data android:path="/sub2"/>
                     <data android:host="example2.com"/>
+                    <data android:host="invalid2."/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <action android:name="android.intent.action.VIEW"/>
@@ -194,6 +208,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub3"/>
                     <data android:host="example3.com"/>
+                    <data android:host=".invalid3"/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <action android:name="android.intent.action.VIEW"/>
@@ -201,6 +216,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub4"/>
                     <data android:host="example4.com"/>
+                    <data android:host="invalid4"/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <action android:name="android.intent.action.VIEW"/>
@@ -208,6 +224,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub5"/>
                     <data android:host="example5.com"/>
+                    <data android:host="invalid5"/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <category android:name="android.intent.category.BROWSABLE"/>
@@ -215,11 +232,12 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub5"/>
                     <data android:host="example5.com"/>
+                    <data android:host="invalid5"/>
                 </intent-filter>
             </xml>
         """.trimIndent()
 
-        return mockThrowOnUnmocked<AndroidPackage> {
+        return mockThrowOnUnmocked {
             whenever(packageName) { TEST_PKG_NAME }
             whenever(targetSdkVersion) {
                 if (useV2) Build.VERSION_CODES.S else Build.VERSION_CODES.R
@@ -238,6 +256,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example1.com", null)
+                                    addDataAuthority("invalid1", null)
                                 }
                         )
                         addIntent(
@@ -248,6 +267,7 @@
                                     addDataScheme("http")
                                     addDataPath("/sub2", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example2.com", null)
+                                    addDataAuthority("invalid2", null)
                                 }
                         )
                     },
@@ -261,6 +281,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub3", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example3.com", null)
+                                    addDataAuthority("invalid3", null)
                                 }
                         )
                     },
@@ -273,6 +294,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub4", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example4.com", null)
+                                    addDataAuthority("invalid4", null)
                                 }
                         )
                         addIntent(
@@ -283,6 +305,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub5", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example5.com", null)
+                                    addDataAuthority("invalid5", null)
                                 }
                         )
                         addIntent(
@@ -293,6 +316,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub6", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example6.com", null)
+                                    addDataAuthority("invalid6", null)
                                 }
                         )
                     },
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
index 9447f39..8ef9239 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
@@ -19,7 +19,7 @@
 import android.content.pm.verify.domain.DomainSet
 import android.content.pm.verify.domain.DomainVerificationInfo
 import android.content.pm.verify.domain.DomainVerificationRequest
-import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.content.pm.verify.domain.DomainVerificationUserState
 import android.os.Parcel
 import android.os.Parcelable
 import android.os.UserHandle
@@ -28,7 +28,6 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 import java.util.UUID
-import kotlin.random.Random
 
 @RunWith(Parameterized::class)
 class DomainVerificationCoreApiTest {
@@ -92,9 +91,9 @@
                 }
             ),
             Parameter(
-                testName = "DomainVerificationUserSelection",
+                testName = "DomainVerificationUserState",
                 initial = {
-                    DomainVerificationUserSelection(
+                    DomainVerificationUserState(
                         UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
                         "com.test.pkg",
                         UserHandle.of(10),
@@ -103,22 +102,22 @@
                             .associate { it.value to (it.index % 3) }
                     )
                 },
-                unparcel = { DomainVerificationUserSelection.CREATOR.createFromParcel(it) },
+                unparcel = { DomainVerificationUserState.CREATOR.createFromParcel(it) },
                 assertion = { first, second ->
-                    assertAll<DomainVerificationUserSelection, UUID>(first, second,
+                    assertAll<DomainVerificationUserState, UUID>(first, second,
                         { it.identifier }, { it.component1() }, IS_EQUAL_TO
                     )
-                    assertAll<DomainVerificationUserSelection, String>(first, second,
+                    assertAll<DomainVerificationUserState, String>(first, second,
                         { it.packageName }, { it.component2() }, IS_EQUAL_TO
                     )
-                    assertAll<DomainVerificationUserSelection, UserHandle>(first, second,
+                    assertAll<DomainVerificationUserState, UserHandle>(first, second,
                         { it.user }, { it.component3() }, IS_EQUAL_TO
                     )
-                    assertAll<DomainVerificationUserSelection, Boolean>(
+                    assertAll<DomainVerificationUserState, Boolean>(
                         first, second, { it.isLinkHandlingAllowed },
                         { it.component4() }, IS_EQUAL_TO
                     )
-                    assertAll<DomainVerificationUserSelection, Map<String, Int>>(
+                    assertAll<DomainVerificationUserState, Map<String, Int>>(
                         first, second, { it.hostToStateMap },
                         { it.component5() }, IS_MAP_EQUAL_TO
                     )
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 89394837..53f0ca2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -155,6 +155,15 @@
                     assertApprovedVerifier(it.callingUid, it.proxy)
                 },
                 enforcer(
+                    Type.SELECTION_QUERENT,
+                    "approvedUserStateQuerent"
+                ) {
+                    assertApprovedUserStateQuerent(
+                        it.callingUid, it.callingUserId,
+                        it.targetPackageName, it.userId
+                    )
+                },
+                enforcer(
                     Type.SELECTOR,
                     "approvedUserSelector"
                 ) {
@@ -170,7 +179,7 @@
                         ArraySet(setOf("example.com"))
                     )
                 },
-                service(Type.INTERNAL, "setUserSelectionInternal") {
+                service(Type.INTERNAL, "setUserStateInternal") {
                     setDomainVerificationUserSelectionInternal(
                         it.userId,
                         it.targetPackageName,
@@ -184,11 +193,11 @@
                 service(Type.INTERNAL, "clearState") {
                     clearDomainVerificationState(listOf(it.targetPackageName))
                 },
-                service(Type.INTERNAL, "clearUserSelections") {
-                    clearUserSelections(listOf(it.targetPackageName), it.userId)
+                service(Type.INTERNAL, "clearUserStates") {
+                    clearUserStates(listOf(it.targetPackageName), it.userId)
                 },
-                service(Type.VERIFIER, "getPackageNames") {
-                    validVerificationPackageNames
+                service(Type.VERIFIER, "queryValidPackageNames") {
+                    queryValidVerificationPackageNames()
                 },
                 service(Type.QUERENT, "getInfo") {
                     getDomainVerificationInfo(it.targetPackageName)
@@ -208,26 +217,13 @@
                         DomainVerificationManager.STATE_SUCCESS
                     )
                 },
-                service(Type.SELECTOR, "setLinkHandlingAllowed") {
-                    setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true)
-                },
                 service(Type.SELECTOR_USER, "setLinkHandlingAllowedUserId") {
                     setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true, it.userId)
                 },
-                service(Type.SELECTOR, "getUserSelection") {
-                    getDomainVerificationUserSelection(it.targetPackageName)
+                service(Type.SELECTION_QUERENT, "getUserStateUserId") {
+                    getDomainVerificationUserState(it.targetPackageName, it.userId)
                 },
-                service(Type.SELECTOR_USER, "getUserSelectionUserId") {
-                    getDomainVerificationUserSelection(it.targetPackageName, it.userId)
-                },
-                service(Type.SELECTOR, "setUserSelection") {
-                    setDomainVerificationUserSelection(
-                        it.targetDomainSetId,
-                        setOf("example.com"),
-                        true
-                    )
-                },
-                service(Type.SELECTOR_USER, "setUserSelectionUserId") {
+                service(Type.SELECTOR_USER, "setUserStateUserId") {
                     setDomainVerificationUserSelection(
                         it.targetDomainSetId,
                         setOf("example.com"),
@@ -244,10 +240,6 @@
                 service(Type.LEGACY_QUERENT, "getLegacyUserState") {
                     getLegacyState(it.targetPackageName, it.userId)
                 },
-                service(Type.OWNER_QUERENT, "getOwnersForDomain") {
-                    // Re-use package name, since the result itself isn't relevant
-                    getOwnersForDomain(it.targetPackageName)
-                },
                 service(Type.OWNER_QUERENT_USER, "getOwnersForDomainUserId") {
                     // Re-use package name, since the result itself isn't relevant
                     getOwnersForDomain(it.targetPackageName, it.userId)
@@ -362,6 +354,7 @@
             Type.INTERNAL -> internal()
             Type.QUERENT -> approvedQuerent()
             Type.VERIFIER -> approvedVerifier()
+            Type.SELECTION_QUERENT -> approvedUserStateQuerent(verifyCrossUser = true)
             Type.SELECTOR -> approvedUserSelector(verifyCrossUser = false)
             Type.SELECTOR_USER -> approvedUserSelector(verifyCrossUser = true)
             Type.LEGACY_QUERENT -> legacyQuerent()
@@ -371,7 +364,7 @@
         }.run { /*exhaust*/ }
     }
 
-    fun internal() {
+    private fun internal() {
         val context: Context = mockThrowOnUnmocked()
         val target = params.construct(context)
 
@@ -385,13 +378,13 @@
         }
     }
 
-    fun approvedQuerent() {
-        val allowUserSelection = AtomicBoolean(false)
+    private fun approvedQuerent() {
+        val allowUserState = AtomicBoolean(false)
         val allowPreferredApps = AtomicBoolean(false)
         val allowQueryAll = AtomicBoolean(false)
         val context: Context = mockThrowOnUnmocked {
             initPermission(
-                allowUserSelection,
+                allowUserState,
                 android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
             )
             initPermission(
@@ -418,7 +411,7 @@
 
         assertFails { runMethod(target, NON_VERIFIER_UID) }
 
-        allowUserSelection.set(true)
+        allowUserState.set(true)
 
         assertFails { runMethod(target, NON_VERIFIER_UID) }
 
@@ -427,7 +420,7 @@
         runMethod(target, NON_VERIFIER_UID)
     }
 
-    fun approvedVerifier() {
+    private fun approvedVerifier() {
         val allowDomainVerificationAgent = AtomicBoolean(false)
         val allowIntentVerificationAgent = AtomicBoolean(false)
         val allowQueryAll = AtomicBoolean(false)
@@ -469,12 +462,61 @@
         assertFails { runMethod(target, NON_VERIFIER_UID) }
     }
 
-    fun approvedUserSelector(verifyCrossUser: Boolean) {
-        val allowUserSelection = AtomicBoolean(false)
+    private fun approvedUserStateQuerent(verifyCrossUser: Boolean) {
         val allowInteractAcrossUsers = AtomicBoolean(false)
         val context: Context = mockThrowOnUnmocked {
             initPermission(
-                allowUserSelection,
+                allowInteractAcrossUsers,
+                android.Manifest.permission.INTERACT_ACROSS_USERS
+            )
+        }
+        val target = params.construct(context)
+
+        fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) {
+            // User selector makes no distinction by UID
+            val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID
+            if (throws) {
+                allUids.forEach {
+                    assertFails {
+                        runMethod(target, it, visible = true, callingUserId, targetUserId)
+                    }
+                }
+            } else {
+                allUids.forEach {
+                    runMethod(target, it, visible = true, callingUserId, targetUserId)
+                }
+            }
+
+            // User selector doesn't use QUERY_ALL, so the invisible package should always fail
+            allUids.forEach {
+                assertFails {
+                    runMethod(target, it, visible = false, callingUserId, targetUserId)
+                }
+            }
+        }
+
+        val callingUserId = 0
+        val notCallingUserId = 1
+
+        runTestCases(callingUserId, callingUserId, throws = false)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = true)
+        }
+
+        allowInteractAcrossUsers.set(true)
+
+        runTestCases(callingUserId, callingUserId, throws = false)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = false)
+        }
+    }
+
+    private fun approvedUserSelector(verifyCrossUser: Boolean) {
+        val allowUserState = AtomicBoolean(false)
+        val allowInteractAcrossUsers = AtomicBoolean(false)
+        val context: Context = mockThrowOnUnmocked {
+            initPermission(
+                allowUserState,
                 android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
             )
             initPermission(
@@ -515,7 +557,7 @@
             runTestCases(callingUserId, notCallingUserId, throws = true)
         }
 
-        allowUserSelection.set(true)
+        allowUserState.set(true)
 
         runTestCases(callingUserId, callingUserId, throws = false)
         if (verifyCrossUser) {
@@ -641,7 +683,7 @@
 
     private fun ownerQuerent(verifyCrossUser: Boolean) {
         val allowQueryAll = AtomicBoolean(false)
-        val allowUserSelection = AtomicBoolean(false)
+        val allowUserState = AtomicBoolean(false)
         val allowInteractAcrossUsers = AtomicBoolean(false)
         val context: Context = mockThrowOnUnmocked {
             initPermission(
@@ -649,7 +691,7 @@
                 android.Manifest.permission.QUERY_ALL_PACKAGES
             )
             initPermission(
-                allowUserSelection,
+                allowUserState,
                 android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
             )
             initPermission(
@@ -690,7 +732,7 @@
             runTestCases(callingUserId, notCallingUserId, throws = true)
         }
 
-        allowUserSelection.set(true)
+        allowUserState.set(true)
 
         runTestCases(callingUserId, callingUserId, throws = false)
         if (verifyCrossUser) {
@@ -769,6 +811,9 @@
         // INTERNAL || domain verification agent
         VERIFIER,
 
+        // No permissions, allows all apps to view domain state for visible packages
+        SELECTION_QUERENT,
+
         // Holding the user setting permission
         SELECTOR,
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
index 439048c..8c31c65 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
@@ -18,7 +18,7 @@
 
 import android.content.pm.verify.domain.DomainVerificationRequest
 import android.content.pm.verify.domain.DomainVerificationInfo
-import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.content.pm.verify.domain.DomainVerificationUserState
 import com.android.server.pm.verify.domain.DomainVerificationPersistence
 
 operator fun <F> android.util.Pair<F, *>.component1() = first
@@ -30,11 +30,11 @@
 operator fun DomainVerificationInfo.component2() = packageName
 operator fun DomainVerificationInfo.component3() = hostToStateMap
 
-operator fun DomainVerificationUserSelection.component1() = identifier
-operator fun DomainVerificationUserSelection.component2() = packageName
-operator fun DomainVerificationUserSelection.component3() = user
-operator fun DomainVerificationUserSelection.component4() = isLinkHandlingAllowed
-operator fun DomainVerificationUserSelection.component5() = hostToStateMap
+operator fun DomainVerificationUserState.component1() = identifier
+operator fun DomainVerificationUserState.component2() = packageName
+operator fun DomainVerificationUserState.component3() = user
+operator fun DomainVerificationUserState.component4() = isLinkHandlingAllowed
+operator fun DomainVerificationUserState.component5() = hostToStateMap
 
 operator fun DomainVerificationPersistence.ReadResult.component1() = active
 operator fun DomainVerificationPersistence.ReadResult.component2() = restored
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
index a92ab9e..6597577 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
@@ -22,14 +22,15 @@
 import android.util.TypedXmlSerializer
 import android.util.Xml
 import com.android.server.pm.verify.domain.DomainVerificationPersistence
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState
 import com.android.server.pm.verify.domain.models.DomainVerificationStateMap
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TemporaryFolder
+import org.xmlpull.v1.XmlPullParser
 import java.io.File
 import java.nio.charset.StandardCharsets
 import java.util.UUID
@@ -41,21 +42,41 @@
 
         internal fun File.writeXml(block: (serializer: TypedXmlSerializer) -> Unit) = apply {
             outputStream().use {
-                // Explicitly use string based XML so it can printed in the test failure output
-                Xml.newFastSerializer()
+                // This must use the binary serializer the mirror the production behavior, as
+                // there are slight differences with the string based one.
+                Xml.newBinarySerializer()
                     .apply {
                         setOutput(it, StandardCharsets.UTF_8.name())
                         startDocument(null, true)
                         setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true)
+                        // Write a wrapping tag to ensure the domain verification settings didn't
+                        // close out the document, allowing other settings to be written
+                        startTag(null, "wrapper-tag")
                     }
                     .apply(block)
+                    .apply {
+                        startTag(null, "trailing-tag")
+                        endTag(null, "trailing-tag")
+                        endTag(null, "wrapper-tag")
+                    }
                     .endDocument()
             }
         }
 
         internal fun <T> File.readXml(block: (parser: TypedXmlPullParser) -> T) =
             inputStream().use {
-                block(Xml.resolvePullParser(it))
+                val parser = Xml.resolvePullParser(it)
+                assertThat(parser.nextTag()).isEqualTo(XmlPullParser.START_TAG)
+                assertThat(parser.name).isEqualTo("wrapper-tag")
+                assertThat(parser.nextTag()).isEqualTo(XmlPullParser.START_TAG)
+                block(parser).also {
+                    assertThat(parser.nextTag()).isEqualTo(XmlPullParser.START_TAG)
+                    assertThat(parser.name).isEqualTo("trailing-tag")
+                    assertThat(parser.nextTag()).isEqualTo(XmlPullParser.END_TAG)
+                    assertThat(parser.name).isEqualTo("trailing-tag")
+                    assertThat(parser.nextTag()).isEqualTo(XmlPullParser.END_TAG)
+                    assertThat(parser.name).isEqualTo("wrapper-tag")
+                }
             }
     }
 
@@ -102,14 +123,14 @@
             // A domain without a written state falls back to default
             stateMap["missing-state.com"] = DomainVerificationManager.STATE_NO_RESPONSE
 
-            userSelectionStates[1] = DomainVerificationUserState(1).apply {
+            userStates[1] = DomainVerificationInternalUserState(1).apply {
                 addHosts(setOf("example-user1.com", "example-user1.org"))
                 isLinkHandlingAllowed = true
             }
         }
         val stateOne = mockEmptyPkgState(1).apply {
             // It's valid to have a user selection without any autoVerify domains
-            userSelectionStates[1] = DomainVerificationUserState(1).apply {
+            userStates[1] = DomainVerificationInternalUserState(1).apply {
                 addHosts(setOf("example-user1.com", "example-user1.org"))
                 isLinkHandlingAllowed = false
             }
@@ -214,7 +235,7 @@
 
     private fun mockPkgState(id: Int) = mockEmptyPkgState(id).apply {
         stateMap["$packageName.com"] = id
-        userSelectionStates[id] = DomainVerificationUserState(id).apply {
+        userStates[id] = DomainVerificationInternalUserState(id).apply {
             addHosts(setOf("$packageName-user.com"))
             isLinkHandlingAllowed = true
         }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
index db541f6..91e5bec 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
@@ -122,7 +122,7 @@
             whenever(setDomainVerificationStatusInternal(anyInt(), any(), any(), anyInt()))
         }
         collector = mockThrowOnUnmocked {
-            whenever(collectAutoVerifyDomains(any())) {
+            whenever(collectValidAutoVerifyDomains(any())) {
                 when (val pkgName = (arguments[0] as AndroidPackage).packageName) {
                     TEST_PKG_NAME_TARGET_ONE -> ArraySet(setOf("example1.com", "example2.com"))
                     TEST_PKG_NAME_TARGET_TWO -> ArraySet(setOf("example3.com", "example4.com"))
@@ -477,7 +477,7 @@
                     whenever(
                         addPowerSaveTempWhitelistApp(
                             anyInt(), anyString(), anyLong(), anyInt(),
-                            anyBoolean(), anyString()
+                            anyBoolean(), anyInt(), anyString()
                         )
                     )
                 }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 010eacf..0d8f275 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -122,8 +122,8 @@
                 service("clearState") {
                     clearDomainVerificationState(listOf(TEST_PKG))
                 },
-                service("clearUserSelections") {
-                    clearUserSelections(listOf(TEST_PKG), TEST_USER_ID)
+                service("clearUserStates") {
+                    clearUserStates(listOf(TEST_PKG), TEST_USER_ID)
                 },
                 service("setStatus") {
                     setDomainVerificationStatus(
@@ -147,19 +147,13 @@
                         DomainVerificationManager.STATE_SUCCESS
                     )
                 },
-                service("setLinkHandlingAllowed") {
-                    setDomainVerificationLinkHandlingAllowed(TEST_PKG, true)
-                },
                 service("setLinkHandlingAllowedUserId") {
                     setDomainVerificationLinkHandlingAllowed(TEST_PKG, true, TEST_USER_ID)
                 },
                 service("setLinkHandlingAllowedInternal") {
                     setDomainVerificationLinkHandlingAllowedInternal(TEST_PKG, true, TEST_USER_ID)
                 },
-                service("setUserSelection") {
-                    setDomainVerificationUserSelection(TEST_UUID, setOf("example.com"), true)
-                },
-                service("setUserSelectionUserId") {
+                service("setUserStateUserId") {
                     setDomainVerificationUserSelection(
                         TEST_UUID,
                         setOf("example.com"),
@@ -167,7 +161,7 @@
                         TEST_USER_ID
                     )
                 },
-                service("setUserSelectionInternal") {
+                service("setUserStateInternal") {
                     setDomainVerificationUserSelectionInternal(
                         TEST_USER_ID,
                         TEST_PKG,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
similarity index 82%
rename from services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
rename to services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 48056a2..0576125 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -16,18 +16,16 @@
 
 package com.android.server.pm.test.verify.domain
 
-import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.content.pm.parsing.component.ParsedActivity
 import android.content.pm.parsing.component.ParsedIntentInfo
 import android.content.pm.verify.domain.DomainVerificationManager
-import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.content.pm.verify.domain.DomainVerificationUserState
 import android.os.Build
 import android.os.PatternMatcher
 import android.os.Process
 import android.util.ArraySet
-import androidx.test.InstrumentationRegistry
 import com.android.server.pm.PackageSetting
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.verify.domain.DomainVerificationService
@@ -41,7 +39,7 @@
 import org.mockito.ArgumentMatchers.anyString
 import java.util.UUID
 
-class DomainVerificationManagerUserSelectionOverrideTest {
+class DomainVerificationUserStateOverrideTest {
 
     companion object {
         private const val PKG_ONE = "com.test.one"
@@ -50,17 +48,19 @@
         private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c")
 
         private val DOMAIN_ONE =
-            DomainVerificationManagerUserSelectionOverrideTest::class.java.packageName
+            DomainVerificationUserStateOverrideTest::class.java.packageName
 
-        private const val STATE_NONE = DomainVerificationUserSelection.DOMAIN_STATE_NONE
-        private const val STATE_SELECTED = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED
-        private const val STATE_VERIFIED = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED
+        private const val STATE_NONE = DomainVerificationUserState.DOMAIN_STATE_NONE
+        private const val STATE_SELECTED = DomainVerificationUserState.DOMAIN_STATE_SELECTED
+        private const val STATE_VERIFIED = DomainVerificationUserState.DOMAIN_STATE_VERIFIED
+
+        private const val USER_ID = 0
     }
 
     private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE)
     private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO)
 
-    fun makeManager(): DomainVerificationManager =
+    fun makeService() =
         DomainVerificationService(mockThrowOnUnmocked {
             // Assume the test has every permission necessary
             whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
@@ -88,7 +88,7 @@
             addPackage(pkg2)
 
             // Starting state for all tests is to have domain 1 enabled for the first package
-            setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true)
+            setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true, USER_ID)
 
             assertThat(stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
         }
@@ -138,37 +138,37 @@
 
     @Test
     fun anotherPackageTakeoverSuccess() {
-        val manager = makeManager()
+        val service = makeService()
 
         // Attempt override by package 2
-        manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+        service.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true, USER_ID)
 
         // 1 loses approval
-        assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
+        assertThat(service.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
 
         // 2 gains approval
-        assertThat(manager.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
+        assertThat(service.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
 
         // 2 is the only owner
-        assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+        assertThat(service.getOwnersForDomain(DOMAIN_ONE, USER_ID).map { it.packageName })
             .containsExactly(PKG_TWO)
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun anotherPackageTakeoverFailure() {
-        val manager = makeManager()
+        val service = makeService()
 
         // Verify 1 to give it a higher approval level
-        manager.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
+        service.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
             DomainVerificationManager.STATE_SUCCESS)
-        assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
-        assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+        assertThat(service.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
+        assertThat(service.getOwnersForDomain(DOMAIN_ONE, USER_ID).map { it.packageName })
             .containsExactly(PKG_ONE)
 
         // Attempt override by package 2
-        manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+        service.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true, USER_ID)
     }
 
-    private fun DomainVerificationManager.stateFor(pkgName: String, host: String) =
-        getDomainVerificationUserSelection(pkgName)!!.hostToStateMap[host]
+    private fun DomainVerificationService.stateFor(pkgName: String, host: String) =
+        getDomainVerificationUserState(pkgName, USER_ID)!!.hostToStateMap[host]
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 9109881..51c9b0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -85,6 +85,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
 import android.app.IActivityManager;
 import android.app.IAlarmCompleteListener;
 import android.app.IAlarmListener;
@@ -1649,8 +1650,8 @@
                 eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
                 eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1669,8 +1670,8 @@
                 eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
                 isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1716,8 +1717,8 @@
                 isNull(), eq(alarmClock), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE),
                 bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1742,8 +1743,8 @@
                 eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(),
                 eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1772,8 +1773,8 @@
                 eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
                 eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1797,8 +1798,8 @@
                 eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
                 isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1822,8 +1823,8 @@
                 eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
                 isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED, type);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 18184b0..f1d8e6c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -592,6 +592,7 @@
                         new DisplayModeDirector.RefreshRateRange(60f, 60f),
                         new DisplayModeDirector.RefreshRateRange(60f, 60f)
                 ));
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
         verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
                 new SurfaceControl.DesiredDisplayModeSpecs(
                         /* baseModeId */ 0,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index f7f5928..3870b02 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -641,6 +641,6 @@
     private static JobStatus createJobStatus(JobInfo.Builder job, int uid,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
         return new JobStatus(job.build(), uid, null, -1, 0, null,
-                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0);
+                earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0, 0);
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 91b3cb7..7925b69 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -685,7 +685,7 @@
         final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
                 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
         return new JobStatus(job, 0, null, -1, 0, null, earliestRunTimeElapsedMillis,
-                latestRunTimeElapsedMillis, 0, 0, null, 0);
+                latestRunTimeElapsedMillis, 0, 0, null, 0, 0);
     }
 
     private static JobStatus createJobStatus(JobInfo job) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index bf95f4c..29db740 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -1326,6 +1326,46 @@
     }
 
     @Test
+    public void testGetMaxJobExecutionTimeLocked_Regular_Active() {
+        JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked_Regular_Active", 0);
+        setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, 2 * HOUR_IN_MILLIS);
+        setDischarging();
+        setStandbyBucket(ACTIVE_INDEX, job);
+        setProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+
+        // ACTIVE apps (where allowed time = window size) should be capped at max execution limit.
+        synchronized (mQuotaController.mLock) {
+            assertEquals(2 * HOUR_IN_MILLIS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+        }
+
+        // Make sure sessions are factored in properly.
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (6 * HOUR_IN_MILLIS),
+                        30 * MINUTE_IN_MILLIS, 1), false);
+        synchronized (mQuotaController.mLock) {
+            assertEquals(90 * MINUTE_IN_MILLIS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+        }
+
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (5 * HOUR_IN_MILLIS),
+                        30 * MINUTE_IN_MILLIS, 1), false);
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (4 * HOUR_IN_MILLIS),
+                        30 * MINUTE_IN_MILLIS, 1), false);
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (3 * HOUR_IN_MILLIS),
+                        25 * MINUTE_IN_MILLIS, 1), false);
+        synchronized (mQuotaController.mLock) {
+            assertEquals(5 * MINUTE_IN_MILLIS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+        }
+    }
+
+    @Test
     public void testGetMaxJobExecutionTimeLocked_EJ() {
         final long timeUsedMs = 3 * MINUTE_IN_MILLIS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
new file mode 100644
index 0000000..d786a5d
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usage;
+
+import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
+import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mockitoSession;
+
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageEvents.Event;
+import android.content.Context;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.usage.UserUsageStatsService.StatsUpdatedListener;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+import java.util.HashMap;
+
+@RunWith(AndroidJUnit4.class)
+public class UserUsageStatsServiceTest {
+    private static final int TEST_USER_ID = 0;
+    private static final String TEST_PACKAGE_NAME = "test.package";
+    private static final long TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
+
+    private UserUsageStatsService mService;
+    private MockitoSession mMockitoSession;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private StatsUpdatedListener mStatsUpdatedListener;
+
+    @Before
+    public void setUp() {
+        mMockitoSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        File dir = new File(InstrumentationRegistry.getContext().getCacheDir(), "test");
+        mService = new UserUsageStatsService(mContext, TEST_USER_ID, dir, mStatsUpdatedListener);
+
+        HashMap<String, Long> installedPkgs = new HashMap<>();
+        installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis());
+
+        mService.init(System.currentTimeMillis(), installedPkgs);
+    }
+
+    @After
+    public void tearDown() {
+        if (mMockitoSession != null) {
+            mMockitoSession.finishMocking();
+        }
+    }
+
+    @Test
+    public void testReportEvent_eventAppearsInQueries() {
+        Event event = new Event(ACTIVITY_RESUMED, SystemClock.elapsedRealtime());
+        event.mPackage = TEST_PACKAGE_NAME;
+        mService.reportEvent(event);
+
+        long now = System.currentTimeMillis();
+        long startTime = now - TIME_INTERVAL_MILLIS;
+        UsageEvents events = mService.queryEventsForPackage(
+                startTime, now, TEST_PACKAGE_NAME, false /* includeTaskRoot */);
+
+        boolean hasTestEvent = false;
+        while (events != null && events.hasNextEvent()) {
+            Event outEvent = new Event();
+            events.getNextEvent(outEvent);
+            if (outEvent.mEventType == ACTIVITY_RESUMED) {
+                hasTestEvent = true;
+            }
+        }
+        assertTrue(hasTestEvent);
+    }
+
+    @Test
+    public void testReportEvent_packageUsedEventNotTracked() {
+        Event event = new Event(APP_COMPONENT_USED, SystemClock.elapsedRealtime());
+        event.mPackage = TEST_PACKAGE_NAME;
+        mService.reportEvent(event);
+
+        long now = System.currentTimeMillis();
+        long startTime = now - TIME_INTERVAL_MILLIS;
+        UsageEvents events = mService.queryEventsForPackage(
+                startTime, now, TEST_PACKAGE_NAME, false /* includeTaskRoot */);
+
+        boolean hasTestEvent = false;
+        while (events != null && events.hasNextEvent()) {
+            Event outEvent = new Event();
+            events.getNextEvent(outEvent);
+            if (outEvent.mEventType == APP_COMPONENT_USED) {
+                hasTestEvent = true;
+            }
+        }
+        assertFalse(hasTestEvent);
+    }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index bea4ae3..68f5479 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -181,9 +181,12 @@
         ":FrameworksServicesTests_install_split_feature_a",
         ":FrameworksServicesTests_install_uses_sdk_0",
         ":FrameworksServicesTests_install_uses_sdk_q0",
-        ":FrameworksServicesTests_install_uses_sdk_r",
+        ":FrameworksServicesTests_install_uses_sdk_q0_r0",
+        ":FrameworksServicesTests_install_uses_sdk_r_none",
         ":FrameworksServicesTests_install_uses_sdk_r0",
         ":FrameworksServicesTests_install_uses_sdk_r5",
+        ":FrameworksServicesTests_install_uses_sdk_r0_s0",
+        ":FrameworksServicesTests_install_uses_sdk_r0_s5",
     ],
     out: ["FrameworkServicesTests_apks_as_resources.res.zip"],
     tools: ["soong_zip"],
diff --git a/services/tests/servicestests/apks/install_uses_sdk/Android.bp b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
index feb152c..a51293d 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/Android.bp
+++ b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
@@ -8,41 +8,49 @@
 }
 
 android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_q0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-q0.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_q0_r0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-q0-r0.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_r_none",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-r-none.xml",
+}
+
+android_test_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_r0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
     manifest: "AndroidManifest-r0.xml",
-
-    srcs: ["**/*.java"],
 }
 
 android_test_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_r5",
     defaults: ["FrameworksServicesTests_apks_defaults"],
     manifest: "AndroidManifest-r5.xml",
-
-    srcs: ["**/*.java"],
 }
 
 android_test_helper_app {
-    name: "FrameworksServicesTests_install_uses_sdk_q0",
+    name: "FrameworksServicesTests_install_uses_sdk_r0_s0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
-    manifest: "AndroidManifest-q0.xml",
-
-    srcs: ["**/*.java"],
+    manifest: "AndroidManifest-r0-s0.xml",
 }
 
 android_test_helper_app {
-    name: "FrameworksServicesTests_install_uses_sdk_r",
+    name: "FrameworksServicesTests_install_uses_sdk_r0_s5",
     defaults: ["FrameworksServicesTests_apks_defaults"],
-    manifest: "AndroidManifest-r.xml",
-
-    srcs: ["**/*.java"],
+    manifest: "AndroidManifest-r0-s5.xml",
 }
 
 android_test_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
     manifest: "AndroidManifest-0.xml",
-
-    srcs: ["**/*.java"],
 }
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
index 215384b..90b13d4 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
@@ -18,7 +18,7 @@
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This is invalid, because there is no sdk version specified -->
-        <extension-sdk android:minExtensionVersion="5" />
+        <extension-sdk android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
similarity index 80%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
index 5d22577..2a32276 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
@@ -17,8 +17,9 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <!-- This fails because 29 doesn't have an extension sdk -->
+        <extension-sdk android:sdkVersion="29" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
similarity index 94%
rename from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
index 5d22577..c79c61c 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
@@ -18,7 +18,7 @@
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <extension-sdk android:sdkVersion="30" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
similarity index 84%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
index 5d22577..af30915 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
@@ -17,8 +17,8 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="31" android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
similarity index 80%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
index 5d22577..bafe4c4 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
@@ -17,8 +17,9 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <!-- This fails because 31 is not version 5 -->
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="31" android:minExtensionVersion="5" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
index c1244f2..2920b86 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
@@ -17,7 +17,7 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
index 3410938..7723d05 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
@@ -18,7 +18,7 @@
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This will fail to install, because minExtensionVersion is not met -->
-        <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="5" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="5" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index cfa2086..f897d5c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -160,6 +160,7 @@
     @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
     @Mock private AccessibilityWindowManager mMockA11yWindowManager;
     @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock private AccessibilityTrace mMockA11yTrace;
     @Mock private WindowManagerInternal mMockWindowManagerInternal;
     @Mock private SystemActionPerformer mMockSystemActionPerformer;
     @Mock private IBinder mMockService;
@@ -188,6 +189,7 @@
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
         when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true);
 
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
         // Fake a11yWindowInfo and remote a11y connection for tests.
         addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false, Display.DEFAULT_DISPLAY);
         addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true, Display.DEFAULT_DISPLAY);
@@ -227,8 +229,8 @@
 
         mServiceConnection = new TestAccessibilityServiceConnection(mMockContext, COMPONENT_NAME,
                 mSpyServiceInfo, SERVICE_ID, mHandler, new Object(), mMockSecurityPolicy,
-                mMockSystemSupport, mMockWindowManagerInternal, mMockSystemActionPerformer,
-                mMockA11yWindowManager);
+                mMockSystemSupport, mMockA11yTrace, mMockWindowManagerInternal,
+                mMockSystemActionPerformer, mMockA11yWindowManager);
         // Assume that the service is connected
         mServiceConnection.mService = mMockService;
         mServiceConnection.mServiceInterface = mMockServiceInterface;
@@ -849,12 +851,13 @@
         TestAccessibilityServiceConnection(Context context, ComponentName componentName,
                 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
                 Object lock, AccessibilitySecurityPolicy securityPolicy,
-                SystemSupport systemSupport, WindowManagerInternal windowManagerInternal,
+                SystemSupport systemSupport, AccessibilityTrace trace,
+                WindowManagerInternal windowManagerInternal,
                 SystemActionPerformer systemActionPerfomer,
                 AccessibilityWindowManager a11yWindowManager) {
             super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
-                    securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer,
-                    a11yWindowManager);
+                    securityPolicy, systemSupport, trace, windowManagerInternal,
+                    systemActionPerfomer, a11yWindowManager);
             mResolvedUserId = USER_ID;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
index 4b2a9fc..80e81d6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
@@ -30,7 +30,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -51,16 +50,19 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.LocalServices;
 import com.android.server.accessibility.gestures.TouchExplorer;
 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
 import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
 import com.android.server.accessibility.magnification.MagnificationGestureHandler;
 import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
+import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
@@ -91,7 +93,9 @@
                     FullScreenMagnificationGestureHandler.class, TouchExplorer.class,
                     AutoclickController.class, AccessibilityInputFilter.class};
 
-    private FullScreenMagnificationController mMockFullScreenMagnificationController;
+    @Mock private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
+    @Mock private WindowManagerInternal mMockWindowManagerService;
+    @Mock private FullScreenMagnificationController mMockFullScreenMagnificationController;
     private AccessibilityManagerService mAms;
     private AccessibilityInputFilter mA11yInputFilter;
     private EventCaptor mCaptor1;
@@ -134,16 +138,21 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         Context context = InstrumentationRegistry.getContext();
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.addService(
+                WindowManagerInternal.class, mMockWindowManagerService);
+        when(mMockWindowManagerService.getAccessibilityController()).thenReturn(
+                mMockA11yController);
+        when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
 
         setDisplayCount(1);
         mAms = spy(new AccessibilityManagerService(context));
-        mMockFullScreenMagnificationController = mock(FullScreenMagnificationController.class);
         mA11yInputFilter = new AccessibilityInputFilter(context, mAms, mEventHandler);
         mA11yInputFilter.onInstalled();
 
-        when(mAms.getValidDisplayList()).thenReturn(mDisplayList);
-        when(mAms.getFullScreenMagnificationController()).thenReturn(
-                mMockFullScreenMagnificationController);
+        doReturn(mDisplayList).when(mAms).getValidDisplayList();
+        doReturn(mMockFullScreenMagnificationController).when(mAms)
+                .getFullScreenMagnificationController();
     }
 
     @After
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 110bb21..bcc756a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -84,6 +84,7 @@
     @Mock private AccessibilityServiceInfo mMockServiceInfo;
     @Mock private ResolveInfo mMockResolveInfo;
     @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
     @Mock private PackageManager mMockPackageManager;
     @Mock private WindowManagerInternal mMockWindowManagerService;
     @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
@@ -115,6 +116,9 @@
 
         when(mMockMagnificationController.getWindowMagnificationMgr()).thenReturn(
                 mMockWindowMagnificationMgr);
+        when(mMockWindowManagerService.getAccessibilityController()).thenReturn(
+                mMockA11yController);
+        when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
         mA11yms = new AccessibilityManagerService(
             InstrumentationRegistry.getContext(),
             mMockPackageManager,
@@ -153,6 +157,7 @@
                 new Object(),
                 mMockSecurityPolicy,
                 mMockSystemSupport,
+                mA11yms,
                 mMockWindowManagerService,
                 mMockSystemActionPerformer,
                 mMockA11yWindowManager,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 6963a1a..00daa5c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -85,6 +85,7 @@
     @Mock AccessibilityWindowManager mMockA11yWindowManager;
     @Mock ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
     @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock AccessibilityTrace mMockA11yTrace;
     @Mock WindowManagerInternal mMockWindowManagerInternal;
     @Mock SystemActionPerformer mMockSystemActionPerformer;
     @Mock KeyEventDispatcher mMockKeyEventDispatcher;
@@ -110,12 +111,13 @@
         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
 
         when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
 
         mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
                 COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
-                mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
-                mMockSystemActionPerformer, mMockA11yWindowManager,
-                mMockActivityTaskManagerInternal);
+                mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
+                mMockWindowManagerInternal, mMockSystemActionPerformer,
+                mMockA11yWindowManager, mMockActivityTaskManagerInternal);
         when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 8062bfe..1603087 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -63,6 +63,7 @@
     @Mock AccessibilitySecurityPolicy mMockSecurityPolicy;
     @Mock AccessibilityWindowManager mMockA11yWindowManager;
     @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock AccessibilityTrace mMockA11yTrace;
     @Mock WindowManagerInternal mMockWindowManagerInternal;
     @Mock SystemActionPerformer mMockSystemActionPerformer;
     @Mock IBinder mMockOwner;
@@ -80,6 +81,7 @@
         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
 
         when(mMockAccessibilityServiceClient.asBinder()).thenReturn(mMockServiceAsBinder);
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
 
         final Context context = getInstrumentation().getTargetContext();
         when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(
@@ -197,7 +199,7 @@
     private void register(int flags) {
         mUiAutomationManager.registerUiTestAutomationServiceLocked(mMockOwner,
                 mMockAccessibilityServiceClient, mMockContext, mMockServiceInfo, SERVICE_ID,
-                mMessageCapturingHandler, mMockSecurityPolicy, mMockSystemSupport,
+                mMessageCapturingHandler, mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
                 mMockWindowManagerInternal, mMockSystemActionPerformer,
                 mMockA11yWindowManager, flags);
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
index 895fb17..5dbf837 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
@@ -69,7 +69,7 @@
         mContext = InstrumentationRegistry.getContext();
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mObserver = new MagnificationGesturesObserver(mCallback, new SimpleSwipe(mContext),
-                new TwoFingersDown(mContext));
+                new TwoFingersDownOrSwipe(mContext));
     }
 
     @Test
@@ -77,9 +77,7 @@
         final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X , DEFAULT_Y);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(moveEvent, moveEvent, 0);
-        });
+        mObserver.onMotionEvent(moveEvent, moveEvent, 0);
 
         verify(mCallback).onGestureCancelled(eq(0L),
                 mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(moveEvent)));
@@ -92,9 +90,7 @@
         final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X , DEFAULT_Y);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(downEvent, downEvent, 0);
-        });
+        mObserver.onMotionEvent(downEvent, downEvent, 0);
 
         verify(mCallback).onGestureCancelled(eq(0L),
                 mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(downEvent)));
@@ -108,9 +104,7 @@
         final int timeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
                 mContext) + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(downEvent, downEvent, 0);
-        });
+        mObserver.onMotionEvent(downEvent, downEvent, 0);
 
         verify(mCallback, timeout(timeoutMillis)).onGestureCancelled(eq(downEvent.getDownTime()),
                 mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(downEvent)));
@@ -121,14 +115,12 @@
     public void sendEventsOfSwiping_onGestureCompleted() {
         final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X, DEFAULT_Y);
-        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop() + 1;
         final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X + swipeDistance, DEFAULT_Y + swipeDistance);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(downEvent, downEvent, 0);
-            mObserver.onMotionEvent(moveEvent, moveEvent, 0);
-        });
+        mObserver.onMotionEvent(downEvent, downEvent, 0);
+        mObserver.onMotionEvent(moveEvent, moveEvent, 0);
 
         verify(mCallback).onGestureCompleted(eq(MagnificationGestureMatcher.GESTURE_SWIPE),
                 eq(downEvent.getDownTime()), mEventInfoArgumentCaptor.capture(),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
index 01631bf21..0ca631e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
@@ -78,7 +78,7 @@
 
     @Test
     public void sendSwipeEvent_onGestureCompleted() {
-        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop() + 1;
         final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X, DEFAULT_Y);
         final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
new file mode 100644
index 0000000..162d2a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility.magnification;
+
+import static com.android.server.accessibility.utils.TouchEventGenerator.movePointer;
+import static com.android.server.accessibility.utils.TouchEventGenerator.twoPointersDownEvents;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.server.accessibility.utils.TouchEventGenerator;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+/**
+ * Tests for {@link TwoFingersDownOrSwipe}.
+ */
+public class TwoFingersDownOrSwipeTest {
+
+    private static final float DEFAULT_X = 100f;
+    private static final float DEFAULT_Y = 100f;
+
+    private static float sSwipeMinDistance;
+    private static int sTimeoutMillis;
+    private static Context sContext;
+
+    private GesturesObserver mGesturesObserver;
+    @Mock
+    private GesturesObserver.Listener mListener;
+
+    @BeforeClass
+    public static void setupOnce() {
+        sContext = InstrumentationRegistry.getContext();
+        sTimeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
+                sContext) + 100;
+        sSwipeMinDistance = ViewConfiguration.get(sContext).getScaledTouchSlop() + 1;
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mGesturesObserver = new GesturesObserver(mListener, new TwoFingersDownOrSwipe(sContext));
+    }
+
+    @Test
+    public void sendSingleDownEvent_GestureCanceledAfterTimeout() {
+        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
+                DEFAULT_X, DEFAULT_Y);
+
+        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
+
+        verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
+                any(MotionEvent.class), eq(0));
+    }
+
+    @Test
+    public void sendTwoFingerDownEvent_onGestureCompleted() {
+        final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+                new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+
+        for (MotionEvent event : downEvents) {
+            mGesturesObserver.onMotionEvent(event, event, 0);
+        }
+
+        verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
+                MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, downEvents.get(1),
+                downEvents.get(1), 0);
+    }
+
+    @Test
+    public void sendSingleTapEvent_onGestureCancelled() {
+        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
+                DEFAULT_X, DEFAULT_Y);
+        final MotionEvent upEvent = TouchEventGenerator.upEvent(Display.DEFAULT_DISPLAY,
+                DEFAULT_X, DEFAULT_Y);
+
+        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
+        mGesturesObserver.onMotionEvent(upEvent, upEvent, 0);
+
+        verify(mListener, after(ViewConfiguration.getDoubleTapTimeout())).onGestureCancelled(
+                any(MotionEvent.class), any(MotionEvent.class), eq(0));
+    }
+
+    @Test
+    public void firstPointerMove_twoPointersDown_onGestureCompleted() {
+        final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+                new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+        for (MotionEvent event : downEvents) {
+            mGesturesObserver.onMotionEvent(event, event, 0);
+        }
+        final MotionEvent moveEvent = movePointer(downEvents.get(1), 0, sSwipeMinDistance, 0);
+
+        mGesturesObserver.onMotionEvent(moveEvent, moveEvent, 0);
+
+        verify(mListener).onGestureCompleted(
+                MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, moveEvent,
+                moveEvent, 0);
+    }
+
+    @Test
+    public void secondPointerMove_twoPointersDown_onGestureCompleted() {
+        final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+                new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+        for (MotionEvent event : downEvents) {
+            mGesturesObserver.onMotionEvent(event, event, 0);
+        }
+        final MotionEvent moveEvent = movePointer(downEvents.get(1), 1, sSwipeMinDistance, 0);
+
+        mGesturesObserver.onMotionEvent(moveEvent, moveEvent, 0);
+
+        verify(mListener).onGestureCompleted(
+                MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, moveEvent,
+                moveEvent, 0);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
deleted file mode 100644
index ed8dc4e..0000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.accessibility.magnification;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.view.Display;
-import android.view.MotionEvent;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.server.accessibility.utils.TouchEventGenerator;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link TwoFingersDown}.
- */
-public class TwoFingersDownTest {
-
-    private static final float DEFAULT_X = 100f;
-    private static final float DEFAULT_Y = 100f;
-
-    private static Context sContext;
-    private static int sTimeoutMillis;
-
-    private Context mContext;
-    private GesturesObserver mGesturesObserver;
-    @Mock
-    private GesturesObserver.Listener mListener;
-
-    @BeforeClass
-    public static void setupOnce() {
-        sContext = InstrumentationRegistry.getContext();
-        sTimeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
-                sContext) + 100;
-    }
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getContext();
-        MockitoAnnotations.initMocks(this);
-        mGesturesObserver = new GesturesObserver(mListener, new TwoFingersDown(mContext));
-    }
-
-    @Test
-    public void sendSingleDownEvent_GestureCanceledAfterTimeout() {
-        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-
-        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-
-        verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
-                any(MotionEvent.class), eq(0));
-    }
-
-    @Test
-    public void sendTwoFingerDownEvent_onGestureCompleted() {
-        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-        final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
-        defPointerCoords.x = DEFAULT_X;
-        defPointerCoords.y = DEFAULT_Y;
-        final MotionEvent.PointerCoords secondPointerCoords = new MotionEvent.PointerCoords();
-        secondPointerCoords.x = DEFAULT_X + 10;
-        secondPointerCoords.y = DEFAULT_Y + 10;
-
-        final MotionEvent twoPointersDownEvent = TouchEventGenerator.twoPointersDownEvent(
-                Display.DEFAULT_DISPLAY, defPointerCoords, secondPointerCoords);
-
-        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-        mGesturesObserver.onMotionEvent(twoPointersDownEvent, twoPointersDownEvent, 0);
-
-        verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
-                MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, twoPointersDownEvent,
-                twoPointersDownEvent, 0);
-    }
-
-    @Test
-    public void sendSingleTapEvent_onGestureCancelled() {
-        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-        final MotionEvent upEvent = TouchEventGenerator.upEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-
-        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-        mGesturesObserver.onMotionEvent(upEvent, upEvent, 0);
-
-        verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
-                any(MotionEvent.class), eq(0));
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 4b7ebbc..b9498d6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -24,13 +24,15 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.DebugUtils;
 import android.view.InputDevice;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.EventStreamTransformation;
@@ -43,6 +45,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
 import java.util.function.IntConsumer;
 
 /**
@@ -75,7 +78,7 @@
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
-        mContext = InstrumentationRegistry.getContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
                 mock(WindowMagnificationManager.Callback.class));
         mMockConnection = new MockWindowMagnificationConnection();
@@ -100,8 +103,8 @@
      * Covers following paths to get to and back between each state and {@link #STATE_IDLE}.
      * <p>
      *     <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"]
-     *     <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"]
-     *     <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"]
+     *     <br> SHOW_MAGNIFIER -> TWO_FINGERS_DOWN [label="2hold"]
+     *     <br> TWO_FINGERS_DOWN -> SHOW_MAGNIFIER [label="release"]
      *     <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"]
      *     <br> IDLE -> SHOW_MAGNIFIER_TRIPLE_TAP [label="3tap"]
      *     <br> SHOW_MAGNIFIER_TRIPLE_TAP -> IDLE [label="3tap"]
@@ -112,18 +115,16 @@
      */
     @Test
     public void testEachState_isReachableAndRecoverable() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            forEachState(state -> {
-                goFromStateIdleTo(state);
-                assertIn(state);
-                returnToNormalFrom(state);
-                try {
-                    assertIn(STATE_IDLE);
-                } catch (AssertionError e) {
-                    throw new AssertionError("Failed while testing state " + stateToString(state),
-                            e);
-                }
-            });
+        forEachState(state -> {
+            goFromStateIdleTo(state);
+            assertIn(state);
+            returnToNormalFrom(state);
+            try {
+                assertIn(STATE_IDLE);
+            } catch (AssertionError e) {
+                throw new AssertionError("Failed while testing state " + stateToString(state),
+                        e);
+            }
         });
     }
 
@@ -209,10 +210,19 @@
                 case STATE_TWO_FINGERS_DOWN: {
                     goFromStateIdleTo(STATE_SHOW_MAGNIFIER_SHORTCUT);
                     final Rect frame = mMockConnection.getMirrorWindowFrame();
-                    send(downEvent(frame.centerX(), frame.centerY()));
-                    //Second finger is outside the window.
-                    send(twoPointerDownEvent(new float[]{frame.centerX(), frame.centerX() + 10},
-                            new float[]{frame.centerY(), frame.centerY() + 10}));
+                    final PointF firstPointerDown = new PointF(frame.centerX(), frame.centerY());
+                    // The second finger is outside the window.
+                    final PointF secondPointerDown = new PointF(frame.right + 10,
+                            frame.bottom + 10);
+                    final List<MotionEvent> motionEvents =
+                            TouchEventGenerator.twoPointersDownEvents(DISPLAY_0,
+                                    firstPointerDown, secondPointerDown);
+                    for (MotionEvent downEvent: motionEvents) {
+                        send(downEvent);
+                    }
+                    // Wait for two-finger down gesture completed.
+                    Thread.sleep(ViewConfiguration.getDoubleTapTimeout());
+                    InstrumentationRegistry.getInstrumentation().waitForIdleSync();
                 }
                 break;
                 case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
@@ -301,16 +311,6 @@
         send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
     }
 
-    private MotionEvent twoPointerDownEvent(float[] x, float[] y) {
-        final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
-        defPointerCoords.x = x[0];
-        defPointerCoords.y = y[0];
-        final MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
-        pointerCoords.x = x[1];
-        pointerCoords.y = y[1];
-        return TouchEventGenerator.twoPointersDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
-    }
-
     private String stateDump() {
         return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
index a05881f..fbcde53 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
@@ -19,16 +19,19 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
-import static android.view.MotionEvent.PointerCoords;
 
+import android.graphics.PointF;
 import android.os.SystemClock;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * generates {@link MotionEvent} with source {@link InputDevice#SOURCE_TOUCHSCREEN}
- *
  */
 public class TouchEventGenerator {
 
@@ -39,44 +42,68 @@
     public static MotionEvent moveEvent(int displayId, float x, float y) {
         return generateSingleTouchEvent(displayId, ACTION_MOVE, x, y);
     }
+
     public static MotionEvent upEvent(int displayId, float x, float y) {
         return generateSingleTouchEvent(displayId, ACTION_UP, x, y);
     }
 
-    public static MotionEvent twoPointersDownEvent(int displayId, PointerCoords defPointerCoords,
-            PointerCoords pointerCoords) {
-        return generateTwoPointersEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
-                pointerCoords);
-    }
-
     private static MotionEvent generateSingleTouchEvent(int displayId, int action, float x,
             float y) {
-        final long  downTime = SystemClock.uptimeMillis();
-        final MotionEvent ev = MotionEvent.obtain(downTime, downTime,
-                action, x, y, 0);
-        ev.setDisplayId(displayId);
-        ev.setSource(InputDevice.SOURCE_TOUCHSCREEN);
-        return ev;
+        return generateMultiplePointersEvent(displayId, action, new PointF(x, y));
     }
 
-    private static MotionEvent generateTwoPointersEvent(int displayId, int action,
-            PointerCoords defPointerCoords, PointerCoords pointerCoords) {
-        final long  downTime = SystemClock.uptimeMillis();
-        MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
-        defPointerProperties.id = 0;
-        defPointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
-        MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
-        pointerProperties.id = 1;
-        pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+    /**
+     * Creates a list of {@link MotionEvent} with given pointers location.
+     *
+     * @param displayId the display id
+     * @param pointF1   location on the screen of the second pointer.
+     * @param pointF2   location on the screen of the second pointer.
+     * @return a list of {@link MotionEvent} with {@link MotionEvent#ACTION_DOWN} and {@link
+     * MotionEvent#ACTION_POINTER_DOWN}.
+     */
+    public static List<MotionEvent> twoPointersDownEvents(int displayId, PointF pointF1,
+            PointF pointF2) {
+        final List<MotionEvent> downEvents = new ArrayList<>();
+        final MotionEvent downEvent = generateMultiplePointersEvent(displayId,
+                MotionEvent.ACTION_DOWN, pointF1);
+        downEvents.add(downEvent);
 
+        final int actionIndex = 1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+        final int action = ACTION_POINTER_DOWN | actionIndex;
+
+        final MotionEvent twoPointersDownEvent = generateMultiplePointersEvent(displayId, action,
+                pointF1, pointF2);
+        downEvents.add(twoPointersDownEvent);
+        return downEvents;
+    }
+
+    private static MotionEvent generateMultiplePointersEvent(int displayId, int action,
+            PointF... pointFs) {
+        final int length = pointFs.length;
+        final MotionEvent.PointerCoords[] pointerCoordsArray =
+                new MotionEvent.PointerCoords[length];
+        final MotionEvent.PointerProperties[] pointerPropertiesArray =
+                new MotionEvent.PointerProperties[length];
+        for (int i = 0; i < length; i++) {
+            MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
+            pointerCoords.x = pointFs[i].x;
+            pointerCoords.y = pointFs[i].y;
+            pointerCoordsArray[i] = pointerCoords;
+
+            MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
+            pointerProperties.id = i;
+            pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+            pointerPropertiesArray[i] = pointerProperties;
+        }
+
+        final long downTime = SystemClock.uptimeMillis();
         final MotionEvent ev = MotionEvent.obtain(
                 /* downTime */ downTime,
                 /* eventTime */ downTime,
                 /* action */ action,
-                /* pointerCount */ 2,
-                /* pointerProperties */ new MotionEvent.PointerProperties[] {
-                        defPointerProperties, pointerProperties},
-                /* pointerCoords */ new PointerCoords[] { defPointerCoords, pointerCoords },
+                /* pointerCount */ length,
+                /* pointerProperties */ pointerPropertiesArray,
+                /* pointerCoords */ pointerCoordsArray,
                 /* metaState */ 0,
                 /* buttonState */ 0,
                 /* xPrecision */ 1.0f,
@@ -88,4 +115,65 @@
         ev.setDisplayId(displayId);
         return ev;
     }
+
+    /**
+     *  Generates a move event that moves the pointer of the original event with given index.
+     *  The original event should not be up event and we don't support
+     *  {@link MotionEvent#ACTION_POINTER_UP} now.
+     *
+     * @param originalEvent the move or down event
+     * @param pointerIndex the index of the pointer we want to move.
+     * @param offsetX the offset in X coordinate.
+     * @param offsetY the offset in Y coordinate.
+     * @return a motion event with move action.
+     */
+    public static MotionEvent movePointer(MotionEvent originalEvent, int pointerIndex,
+            float offsetX, float offsetY) {
+        if (originalEvent.getActionMasked() == ACTION_UP) {
+            throw new IllegalArgumentException("No pointer is on the screen");
+        }
+
+        if (originalEvent.getActionMasked() == ACTION_POINTER_UP) {
+            throw new IllegalArgumentException("unsupported yet,please implement it first");
+        }
+
+        final int pointerCount = originalEvent.getPointerCount();
+        if (pointerIndex >= pointerCount) {
+            throw new IllegalArgumentException(
+                    pointerIndex + "is not available with pointer count" + pointerCount);
+        }
+        final int action = MotionEvent.ACTION_MOVE;
+        final MotionEvent.PointerProperties[] pp = new MotionEvent.PointerProperties[pointerCount];
+        for (int i = 0; i < pointerCount; i++) {
+            MotionEvent.PointerProperties pointerProperty = new MotionEvent.PointerProperties();
+            originalEvent.getPointerProperties(i, pointerProperty);
+            pp[i] = pointerProperty;
+        }
+
+        final MotionEvent.PointerCoords[] pc = new MotionEvent.PointerCoords[pointerCount];
+        for (int i = 0; i < pointerCount; i++) {
+            MotionEvent.PointerCoords pointerCoord = new MotionEvent.PointerCoords();
+            originalEvent.getPointerCoords(i, pointerCoord);
+            pc[i] = pointerCoord;
+        }
+        pc[pointerIndex].x += offsetX;
+        pc[pointerIndex].y += offsetY;
+        final MotionEvent ev = MotionEvent.obtain(
+                /* downTime */ originalEvent.getDownTime(),
+                /* eventTime */ SystemClock.uptimeMillis(),
+                /* action */ action,
+                /* pointerCount */ 2,
+                /* pointerProperties */ pp,
+                /* pointerCoords */ pc,
+                /* metaState */ 0,
+                /* buttonState */ 0,
+                /* xPrecision */ 1.0f,
+                /* yPrecision */ 1.0f,
+                /* deviceId */ 0,
+                /* edgeFlags */ 0,
+                /* source */ originalEvent.getSource(),
+                /* flags */ originalEvent.getFlags());
+        ev.setDisplayId(originalEvent.getDisplayId());
+        return ev;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 8b0e948..b6b6932 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -602,12 +602,12 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
         when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
-                                .withPackageName("foo.bar")
-                                .debuggable()
-                                .build());
+                        .withPackageName("foo.bar")
+                        .debuggable()
+                        .build());
         when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
                 .thenThrow(new NameNotFoundException());
 
@@ -649,7 +649,7 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
 
         compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L,
                 new PackageOverride.Builder()
@@ -673,11 +673,11 @@
     }
 
     @Test
-    public void testLoadOverridesRaw() throws Exception {
+    public void testInitOverridesRaw() throws Exception {
         File tempDir = createTempDir();
         File overridesFile = new File(tempDir, "overrides.xml");
         // Change 1 is enabled for foo.bar (validated)
-        // Change 2 is disabled for bar.baz (deferred)
+        // Change 2 is disabled for bar.baz (raw)
         String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                 + "<overrides>\n"
                 + "    <change-overrides changeId=\"1\">\n"
@@ -709,7 +709,7 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("foo.bar")
                 .withVersionCode(100L)
@@ -728,7 +728,7 @@
     }
 
     @Test
-    public void testLoadOverridesDeferred() throws Exception {
+    public void testInitOverridesDeferred() throws Exception {
         File tempDir = createTempDir();
         File overridesFile = new File(tempDir, "overrides.xml");
         // Change 1 is enabled for foo.bar (validated)
@@ -754,7 +754,7 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("foo.bar")
                 .debuggable()
@@ -767,4 +767,115 @@
         assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
         assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
     }
+
+    @Test
+    public void testInitOverridesWithStaticFile() throws Exception {
+        File tempDir = createTempDir();
+        File dynamicOverridesFile = new File(tempDir, "dynamic_overrides.xml");
+        File staticOverridesFile = new File(tempDir, "static_overrides.xml");
+        // Change 1 is enabled for foo.bar (raw)
+        // Change 2 is disabled for bar.baz (raw)
+        String dynamicXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<overrides>"
+                +    "<change-overrides changeId=\"1\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                +    "<change-overrides changeId=\"2\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                + "</overrides>";
+        writeToFile(tempDir, "dynamic_overrides.xml", dynamicXmlData);
+        // Change 2 is enabled for foo.bar and bar.baz (raw)
+        // Change 3 is enabled for bar.baz (raw)
+        String staticXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<overrides>"
+                +    "<change-overrides changeId=\"2\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                +    "<change-overrides changeId=\"3\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                + "</overrides>";
+        writeToFile(tempDir, "static_overrides.xml", staticXmlData);
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1L)
+                .addDisabledChangeWithId(2L)
+                .addDisabledChangeWithId(3L)
+                .build();
+        compatConfig.forceNonDebuggableFinalForTest(true);
+        // Adding an override that will be cleared after initOverrides is called.
+        compatConfig.addOverride(1L, "bar.baz", true);
+        compatConfig.initOverrides(dynamicOverridesFile, staticOverridesFile);
+        when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+                .thenThrow(new NameNotFoundException());
+        when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+                .thenThrow(new NameNotFoundException());
+
+        assertThat(compatConfig.willChangeBeEnabled(1L, "foo.bar")).isTrue();
+        assertThat(compatConfig.willChangeBeEnabled(2L, "foo.bar")).isTrue();
+        assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+        assertThat(compatConfig.willChangeBeEnabled(3L, "bar.baz")).isTrue();
+        assertThat(readFile(dynamicOverridesFile))
+                .isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+                + "<overrides>\n"
+                + "    <change-overrides changeId=\"1\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "    <change-overrides changeId=\"2\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "    <change-overrides changeId=\"3\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "</overrides>\n");
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index a078a77..a97ea26 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -21,8 +21,10 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertThrows;
 
+import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateRequest;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
 import android.os.Binder;
@@ -33,10 +35,13 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Optional;
 
@@ -70,14 +75,14 @@
     public void baseStateChanged() {
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
     }
@@ -89,21 +94,21 @@
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -116,7 +121,7 @@
 
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -129,16 +134,19 @@
 
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
 
     @Test
-    public void supportedStatesChanged() {
+    public void supportedStatesChanged() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
 
@@ -146,27 +154,44 @@
         // supported.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+
+        assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
+                new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
     }
 
     @Test
-    public void supportedStatesChanged_unsupportedBaseState() {
+    public void supportedStatesChanged_statesRemainSame() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
 
-        mProvider.notifySupportedDeviceStates(new DeviceState[]{ OTHER_DEVICE_STATE });
+        mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
+                OTHER_DEVICE_STATE });
 
-        // The current requested state is cleared because it is no longer supported.
+        // The current committed and requests states do not change because the current state remains
+        // supported.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), Optional.empty());
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
 
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        // The callback wasn't notified about a change in supported states as the states have not
+        // changed.
+        assertNull(callback.getLastNotifiedInfo());
+    }
 
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+    @Test
+    public void getDeviceStateInfo() throws RemoteException {
+        DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+        assertNotNull(info);
+        assertArrayEquals(info.supportedStates,
+                new int[] { DEFAULT_DEVICE_STATE.getIdentifier(),
+                        OTHER_DEVICE_STATE.getIdentifier() });
+        assertEquals(info.baseState, DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
     }
 
     @Test
@@ -175,41 +200,33 @@
         mService.getBinderService().registerCallback(callback);
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
-        assertNotNull(callback.getLastNotifiedValue());
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                OTHER_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.blockConfigure();
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
         // The callback should not have been notified of the state change as the policy is still
         // pending callback.
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
         // Now that the policy is finished processing the callback should be notified of the state
         // change.
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
                 OTHER_DEVICE_STATE.getIdentifier());
-    }
-
-    @Test
-    public void registerCallback_emitsInitialValue() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
-        mService.getBinderService().registerCallback(callback);
-        assertNotNull(callback.getLastNotifiedValue());
-        assertEquals(callback.getLastNotifiedValue().intValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
-    }
-
-    @Test
-    public void getSupportedDeviceStates() throws RemoteException {
-        final int[] expectedStates = new int[] { 0, 1 };
-        assertEquals(mService.getBinderService().getSupportedDeviceStates(), expectedStates);
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                OTHER_DEVICE_STATE.getIdentifier());
     }
 
     @Test
@@ -228,11 +245,16 @@
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
+        assertNotNull(callback.getLastNotifiedInfo());
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                OTHER_DEVICE_STATE.getIdentifier());
 
         mService.getBinderService().cancelRequest(token);
 
@@ -240,10 +262,96 @@
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
+
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+    }
+
+    @Test
+    public void requestState_pendingStateAtRequest() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
+        mPolicy.blockConfigure();
+
+        final IBinder firstRequestToken = new Binder();
+        final IBinder secondRequestToken = new Binder();
+        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+        mService.getBinderService().requestState(firstRequestToken,
+                OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+
+        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                OTHER_DEVICE_STATE.getIdentifier());
+
+        mService.getBinderService().requestState(secondRequestToken,
+                DEFAULT_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+
+        mPolicy.resumeConfigureOnce();
+
+        // First request status is now suspended as there is another pending request.
+        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
+                TestDeviceStateManagerCallback.STATUS_SUSPENDED);
+        // Second request status still unknown because the service is still awaiting policy
+        // callback.
+        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getPendingState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                DEFAULT_DEVICE_STATE.getIdentifier());
+
+        mPolicy.resumeConfigure();
+
+        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getPendingState(), Optional.empty());
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                DEFAULT_DEVICE_STATE.getIdentifier());
+
+        // Now cancel the second request to make the first request active.
+        mService.getBinderService().cancelRequest(secondRequestToken);
+
+        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
+                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
+                TestDeviceStateManagerCallback.STATUS_CANCELED);
+
+        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getPendingState(), Optional.empty());
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                OTHER_DEVICE_STATE.getIdentifier());
+    }
+
+    @Test
+    public void requestState_sameAsBaseState() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
+        final IBinder token = new Binder();
+        assertEquals(callback.getLastNotifiedStatus(token),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+        mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
+                0 /* flags */);
+
+        assertEquals(callback.getLastNotifiedStatus(token),
+                TestDeviceStateManagerCallback.STATUS_ACTIVE);
     }
 
     @Test
@@ -263,7 +371,7 @@
 
         // Committed state changes as there is a requested override.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -275,7 +383,7 @@
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -297,7 +405,7 @@
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -310,7 +418,7 @@
         // Committed state is set back to the requested state as the override state is no longer
         // supported.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
@@ -348,6 +456,10 @@
         });
     }
 
+    private static void assertArrayEquals(int[] expected, int[] actual) {
+        Assert.assertTrue(Arrays.equals(expected, actual));
+    }
+
     private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
         private final DeviceStateProvider mProvider;
         private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
@@ -376,6 +488,14 @@
             }
         }
 
+        public void resumeConfigureOnce() {
+            if (mPendingConfigureCompleteRunnable != null) {
+                Runnable onComplete = mPendingConfigureCompleteRunnable;
+                mPendingConfigureCompleteRunnable = null;
+                onComplete.run();
+            }
+        }
+
         public int getMostRecentRequestedStateToConfigure() {
             return mLastDeviceStateRequestedToConfigure;
         }
@@ -429,12 +549,14 @@
         public static final int STATUS_SUSPENDED = 2;
         public static final int STATUS_CANCELED = 3;
 
-        private Integer mLastNotifiedValue;
+        @Nullable
+        private DeviceStateInfo mLastNotifiedInfo;
+        private boolean mNotifiedOfChangeInSupportedStates;
         private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
 
         @Override
-        public void onDeviceStateChanged(int deviceState) {
-            mLastNotifiedValue = deviceState;
+        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+            mLastNotifiedInfo = info;
         }
 
         @Override
@@ -453,8 +575,8 @@
         }
 
         @Nullable
-        Integer getLastNotifiedValue() {
-            return mLastNotifiedValue;
+        DeviceStateInfo getLastNotifiedInfo() {
+            return mLastNotifiedInfo;
         }
 
         int getLastNotifiedStatus(IBinder requestToken) {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 81b2381..15ada89 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -88,6 +88,7 @@
     private static final String TAG = "DisplayModeDirectorTest";
     private static final boolean DEBUG = false;
     private static final float FLOAT_TOLERANCE = 0.01f;
+    private static final int DISPLAY_ID = 0;
 
     private Context mContext;
     private FakesInjector mInjector;
@@ -107,19 +108,29 @@
 
     private DisplayModeDirector createDirectorFromRefreshRateArray(
             float[] refreshRates, int baseModeId) {
+        return createDirectorFromRefreshRateArray(refreshRates, baseModeId, refreshRates[0]);
+    }
+
+    private DisplayModeDirector createDirectorFromRefreshRateArray(
+            float[] refreshRates, int baseModeId, float defaultRefreshRate) {
         DisplayModeDirector director =
                 new DisplayModeDirector(mContext, mHandler, mInjector);
-        int displayId = 0;
         Display.Mode[] modes = new Display.Mode[refreshRates.length];
+        Display.Mode defaultMode = null;
         for (int i = 0; i < refreshRates.length; i++) {
             modes[i] = new Display.Mode(
                     /*modeId=*/baseModeId + i, /*width=*/1000, /*height=*/1000, refreshRates[i]);
+            if (refreshRates[i] == defaultRefreshRate) {
+                defaultMode = modes[i];
+            }
         }
+        assertThat(defaultMode).isNotNull();
+
         SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
-        supportedModesByDisplay.put(displayId, modes);
+        supportedModesByDisplay.put(DISPLAY_ID, modes);
         director.injectSupportedModesByDisplay(supportedModesByDisplay);
         SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>();
-        defaultModesByDisplay.put(displayId, modes[0]);
+        defaultModesByDisplay.put(DISPLAY_ID, defaultMode);
         director.injectDefaultModeByDisplay(defaultModesByDisplay);
         return director;
     }
@@ -130,16 +141,15 @@
         for (int i = 0; i < numRefreshRates; i++) {
             refreshRates[i] = minFps + i;
         }
-        return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps);
+        return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps,
+                /*defaultRefreshRate=*/minFps);
     }
 
     @Test
     public void testDisplayModeVoting() {
-        int displayId = 0;
-
         // With no votes present, DisplayModeDirector should allow any refresh rate.
         DesiredDisplayModeSpecs modeSpecs =
-                createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(displayId);
+                createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(modeSpecs.baseModeId).isEqualTo(60);
         assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(0f);
         assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(Float.POSITIVE_INFINITY);
@@ -156,12 +166,12 @@
             assertTrue(2 * numPriorities < maxFps - minFps + 1);
             SparseArray<Vote> votes = new SparseArray<>();
             SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-            votesByDisplay.put(displayId, votes);
+            votesByDisplay.put(DISPLAY_ID, votes);
             for (int i = 0; i < numPriorities; i++) {
                 int priority = Vote.MIN_PRIORITY + i;
                 votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
                 director.injectVotesByDisplay(votesByDisplay);
-                modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+                modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
                 assertThat(modeSpecs.baseModeId).isEqualTo(minFps + i);
                 assertThat(modeSpecs.primaryRefreshRateRange.min)
                         .isEqualTo((float) (minFps + i));
@@ -177,11 +187,11 @@
             DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
             SparseArray<Vote> votes = new SparseArray<>();
             SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-            votesByDisplay.put(displayId, votes);
+            votesByDisplay.put(DISPLAY_ID, votes);
             votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
             votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
             director.injectVotesByDisplay(votesByDisplay);
-            modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+            modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
             assertThat(modeSpecs.baseModeId).isEqualTo(70);
             assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(70f);
             assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(80f);
@@ -190,18 +200,17 @@
 
     @Test
     public void testVotingWithFloatingPointErrors() {
-        int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         float error = FLOAT_TOLERANCE / 4;
         votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60));
         votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error));
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE,
                 Vote.forRefreshRates(60 - error, 60 - error));
         director.injectVotesByDisplay(votesByDisplay);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -213,15 +222,14 @@
         assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
         assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
 
-        int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
 
@@ -229,7 +237,7 @@
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
 
@@ -237,7 +245,7 @@
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
 
@@ -245,7 +253,7 @@
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
     }
@@ -261,14 +269,13 @@
         assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
                 >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
 
-        int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
@@ -277,7 +284,7 @@
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
                 Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
@@ -285,7 +292,7 @@
 
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(75, 75));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min)
@@ -355,11 +362,10 @@
 
     @Test
     public void testVotingWithAlwaysRespectAppRequest() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(0, 60));
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
@@ -369,7 +375,7 @@
 
         director.injectVotesByDisplay(votesByDisplay);
         assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -377,7 +383,7 @@
 
         director.setShouldAlwaysRespectAppRequestedMode(true);
         assertThat(director.shouldAlwaysRespectAppRequestedMode()).isTrue();
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.baseModeId).isEqualTo(90);
@@ -385,7 +391,7 @@
         director.setShouldAlwaysRespectAppRequestedMode(false);
         assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
 
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(60);
@@ -393,11 +399,10 @@
 
     @Test
     public void testVotingWithSwitchingTypeNone() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(30, 90));
         votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
 
@@ -405,7 +410,7 @@
         director.injectVotesByDisplay(votesByDisplay);
         assertThat(director.getModeSwitchingType())
                 .isNotEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -417,7 +422,7 @@
         assertThat(director.getModeSwitchingType())
                 .isEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
 
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
@@ -427,29 +432,38 @@
 
     @Test
     public void testVotingWithSwitchingTypeWithinGroups() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
 
         director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS);
         assertThat(director.getModeSwitchingType())
                 .isEqualTo(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.allowGroupSwitching).isFalse();
     }
 
     @Test
     public void testVotingWithSwitchingTypeWithinAndAcrossGroups() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
 
         director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
         assertThat(director.getModeSwitchingType())
                 .isEqualTo(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.allowGroupSwitching).isTrue();
     }
 
     @Test
+    public void testDefaultDisplayModeIsSelectedIfAvailable() {
+        final float[] refreshRates = new float[]{24f, 25f, 30f, 60f, 90f};
+        final int defaultModeId = 3;
+        DisplayModeDirector director = createDirectorFromRefreshRateArray(
+                refreshRates, /*baseModeId=*/0, refreshRates[defaultModeId]);
+
+        DesiredDisplayModeSpecs specs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+        assertThat(specs.baseModeId).isEqualTo(defaultModeId);
+    }
+
+    @Test
     public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() {
         DisplayModeDirector director =
                 createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 92221c9..bcd853c 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -94,8 +94,7 @@
         // Disable binder caches in this process.
         PropertyInvalidatedCache.disableForTestMode();
 
-        mLogicalDisplayMapper = new LogicalDisplayMapper(
-                mContext, mDisplayDeviceRepo, mListenerMock);
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, mListenerMock);
     }
 
 
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java
deleted file mode 100644
index 275e7c7..0000000
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.graphics.fonts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.FileUtils;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-
-@Presubmit
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class FontCrashDetectorTest {
-
-    private File mCacheDir;
-
-    @SuppressWarnings("ResultOfMethodCallIgnored")
-    @Before
-    public void setUp() {
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        mCacheDir = new File(context.getCacheDir(), "UpdatableFontDirTest");
-        FileUtils.deleteContentsAndDir(mCacheDir);
-        mCacheDir.mkdirs();
-    }
-
-    @Test
-    public void detectCrash() throws Exception {
-        // Prepare a marker file.
-        File file = new File(mCacheDir, "detectCrash");
-        assertThat(file.createNewFile()).isTrue();
-
-        FontCrashDetector detector = new FontCrashDetector(file);
-        assertThat(detector.hasCrashed()).isTrue();
-
-        detector.clear();
-        assertThat(detector.hasCrashed()).isFalse();
-        assertThat(file.exists()).isFalse();
-    }
-
-    @Test
-    public void monitorCrash() {
-        File file = new File(mCacheDir, "monitorCrash");
-        FontCrashDetector detector = new FontCrashDetector(file);
-        assertThat(detector.hasCrashed()).isFalse();
-
-        FontCrashDetector.MonitoredBlock block = detector.start();
-        assertThat(file.exists()).isTrue();
-
-        block.close();
-        assertThat(file.exists()).isFalse();
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index f2254a9..c08857c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -74,8 +74,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         mHdmiControlService = new HdmiControlService(mContextSpy) {
             @Override
             AudioManager getAudioManager() {
@@ -106,15 +104,11 @@
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
 
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 44418ce..50ba761 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -76,8 +76,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy) {
                     @Override
@@ -112,11 +110,6 @@
                     Looper getServiceLooper() {
                         return mTestLooper.getLooper();
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -128,6 +121,7 @@
         mHdmiCecLocalDeviceAudioSystem.init();
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
+        hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index d454d87..aa5bc93 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -77,8 +77,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy) {
                     @Override
@@ -113,15 +111,11 @@
                     Looper getServiceLooper() {
                         return mTestLooper.getLooper();
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
+        hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index 7cb72c4..ef7b274 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -86,8 +86,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         mHdmiControlService = new HdmiControlService(mContextSpy) {
             @Override
             AudioManager getAudioManager() {
@@ -118,15 +116,11 @@
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
 
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
index 9bf95c0..678f8b2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
@@ -106,8 +106,6 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                     @Override
@@ -133,16 +131,12 @@
                     protected PowerManager getPowerManager() {
                         return powerManager;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
         mHdmiCecLocalDeviceTv.init();
         mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index eedbc95..6bb148d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -98,8 +98,6 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
             new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                 @Override
@@ -188,17 +186,13 @@
                 protected PowerManager getPowerManager() {
                     return powerManager;
                 }
-
-                @Override
-                protected HdmiCecConfig getHdmiCecConfig() {
-                    return hdmiCecConfig;
-                }
             };
 
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
         mMyLooper = mTestLooper.getLooper();
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
         mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index b11ac24..915392e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -87,7 +87,6 @@
         mMyLooper = mTestLooper.getLooper();
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
 
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -136,15 +135,11 @@
                     protected PowerManager getPowerManager() {
                         return powerManager;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
         mHdmiCecLocalDevicePlayback.init();
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mHdmiControlService.setIoLooper(mMyLooper);
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 0717112..b3f0085 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -128,8 +128,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
                 new HdmiControlService(context) {
                     @Override
@@ -163,13 +161,9 @@
                     void wakeUp() {
                         mWakeupMessageReceived = true;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
         mHdmiControlService.setIoLooper(mTestLooper.getLooper());
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 4623eb5..4b3ef2f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -81,8 +81,6 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                     @Override
@@ -119,16 +117,12 @@
                     AudioManager getAudioManager() {
                         return mAudioManager;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
         mHdmiCecLocalDeviceTv.init();
         mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 06373c2..1c7ff42 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -62,12 +62,12 @@
     private FakeNativeWrapper mNativeWrapper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
-    private int mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_B;
     @Mock
     private IPowerManager mIPowerManagerMock;
     @Mock
     private IThermalService mIThermalServiceMock;
     private HdmiControlService mHdmiControlService;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
 
     @Before
     public void setUp() throws Exception {
@@ -81,8 +81,6 @@
         when(contextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(contextSpy);
-
         mHdmiControlService = new HdmiControlService(contextSpy) {
             @Override
             boolean isControlEnabled() {
@@ -100,33 +98,24 @@
             }
 
             @Override
-            int getCecVersion() {
-                return mHdmiCecVersion;
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
         mHdmiControlService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
-        HdmiCecLocalDevicePlayback hdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
-        hdmiCecLocalDevicePlayback.init();
+        mHdmiCecLocalDevicePlayback.init();
         mHdmiControlService.setIoLooper(myLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(contextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
         mHdmiControlService.setCecController(hdmiCecController);
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
-        mLocalDevices.add(hdmiCecLocalDevicePlayback);
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
         HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
         hdmiPortInfos[0] =
                 new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
@@ -188,77 +177,84 @@
 
     @Test
     public void setPowerStatus_doesntSendBroadcast_1_4() {
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
         mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_transient_doesntSendBroadcast_1_4() {
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_fast_transient_doesntSendBroadcast_1_4() {
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_sendsBroadcast_2_0() {
-        mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_ON);
         assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_transient_sendsBroadcast_2_0() {
-        mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_fast_transient_doesntSendBroadcast_2_0() {
-        mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
+
+    private void setCecVersion(int version) {
+        mHdmiControlService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, version);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 32a7048..47f3bf9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -19,6 +19,7 @@
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
 
 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
+import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -44,12 +45,12 @@
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -68,14 +69,64 @@
 @RunWith(JUnit4.class)
 public class HdmiControlServiceTest {
 
-    private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource {
+    private class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
 
         private boolean mCanGoToStandby;
         private boolean mIsStandby;
         private boolean mIsDisabled;
 
-        protected HdmiCecLocalDeviceMyDevice(HdmiControlService service, int deviceType) {
-            super(service, deviceType);
+        MockPlaybackDevice(HdmiControlService service) {
+            super(service);
+        }
+
+        @Override
+        protected void onAddressAllocated(int logicalAddress, int reason) {}
+
+        @Override
+        protected int getPreferredAddress() {
+            return 0;
+        }
+
+        @Override
+        protected void setPreferredAddress(int addr) {}
+
+        @Override
+        protected boolean canGoToStandby() {
+            return mCanGoToStandby;
+        }
+
+        @Override
+        protected void disableDevice(
+                boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
+            mIsDisabled = true;
+            originalCallback.onCleared(this);
+        }
+
+        @Override
+        protected void onStandby(boolean initiatedByCec, int standbyAction) {
+            mIsStandby = true;
+        }
+
+        protected boolean isStandby() {
+            return mIsStandby;
+        }
+
+        protected boolean isDisabled() {
+            return mIsDisabled;
+        }
+
+        protected void setCanGoToStandby(boolean canGoToStandby) {
+            mCanGoToStandby = canGoToStandby;
+        }
+    }
+    private class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem {
+
+        private boolean mCanGoToStandby;
+        private boolean mIsStandby;
+        private boolean mIsDisabled;
+
+        MockAudioSystemDevice(HdmiControlService service) {
+            super(service);
         }
 
         @Override
@@ -123,8 +174,8 @@
     private Context mContextSpy;
     private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
-    private HdmiCecLocalDeviceMyDevice mMyAudioSystemDevice;
-    private HdmiCecLocalDeviceMyDevice mMyPlaybackDevice;
+    private MockAudioSystemDevice mAudioSystemDevice;
+    private MockPlaybackDevice mPlaybackDevice;
     private FakeNativeWrapper mNativeWrapper;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
@@ -144,6 +195,7 @@
         PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
                 mIThermalServiceMock, null);
         when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
@@ -157,21 +209,17 @@
             @Override
             protected void writeStringSystemProperty(String key, String value) {
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
         mMyLooper = mTestLooper.getLooper();
 
-        mMyAudioSystemDevice =
-                new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_AUDIO_SYSTEM);
-        mMyPlaybackDevice = new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_PLAYBACK);
-        mMyAudioSystemDevice.init();
-        mMyPlaybackDevice.init();
+        mAudioSystemDevice = new MockAudioSystemDevice(mHdmiControlService);
+        mPlaybackDevice = new MockPlaybackDevice(mHdmiControlService);
+        mAudioSystemDevice.init();
+        mPlaybackDevice.init();
 
         mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(hdmiCecConfig);
+        mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
 
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
@@ -180,8 +228,8 @@
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
 
-        mLocalDevices.add(mMyAudioSystemDevice);
-        mLocalDevices.add(mMyPlaybackDevice);
+        mLocalDevices.add(mAudioSystemDevice);
+        mLocalDevices.add(mPlaybackDevice);
         mHdmiPortInfo = new HdmiPortInfo[4];
         mHdmiPortInfo[0] =
             new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
@@ -192,6 +240,9 @@
         mHdmiPortInfo[3] =
             new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
         mNativeWrapper.setPortInfo(mHdmiPortInfo);
+        mHdmiControlService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlService.initService();
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
 
@@ -201,13 +252,13 @@
     @Test
     public void onStandby_notByCec_cannotGoToStandby() {
         mStandbyMessageReceived = false;
-        mMyPlaybackDevice.setCanGoToStandby(false);
+        mPlaybackDevice.setCanGoToStandby(false);
 
         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
-        assertTrue(mMyPlaybackDevice.isStandby());
-        assertTrue(mMyAudioSystemDevice.isStandby());
-        assertFalse(mMyPlaybackDevice.isDisabled());
-        assertFalse(mMyAudioSystemDevice.isDisabled());
+        assertTrue(mPlaybackDevice.isStandby());
+        assertTrue(mAudioSystemDevice.isStandby());
+        assertFalse(mPlaybackDevice.isDisabled());
+        assertFalse(mAudioSystemDevice.isDisabled());
     }
 
     @Test
@@ -215,10 +266,10 @@
         mStandbyMessageReceived = true;
 
         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
-        assertTrue(mMyPlaybackDevice.isStandby());
-        assertTrue(mMyAudioSystemDevice.isStandby());
-        assertTrue(mMyPlaybackDevice.isDisabled());
-        assertTrue(mMyAudioSystemDevice.isDisabled());
+        assertTrue(mPlaybackDevice.isStandby());
+        assertTrue(mAudioSystemDevice.isStandby());
+        assertTrue(mPlaybackDevice.isDisabled());
+        assertTrue(mAudioSystemDevice.isDisabled());
     }
 
     @Test
@@ -275,6 +326,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mTestLooper.dispatchAll();
 
         mHdmiControlService.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mNativeWrapper.clearResultMessages();
@@ -555,8 +607,8 @@
         HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
-                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
-                mMyPlaybackDevice.getDeviceFeatures());
+                mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+                mPlaybackDevice.getDeviceFeatures());
         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
     }
 
@@ -573,8 +625,8 @@
         HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
-                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
-                mMyPlaybackDevice.getDeviceFeatures());
+                mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+                mPlaybackDevice.getDeviceFeatures());
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportFeatures);
     }
 
@@ -590,8 +642,8 @@
         HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
-                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
-                mMyPlaybackDevice.getDeviceFeatures());
+                mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+                mPlaybackDevice.getDeviceFeatures());
         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
     }
 
@@ -612,41 +664,42 @@
         assertEquals(runnerUid, Binder.getCallingWorkSourceUid());
     }
 
-    @Ignore("b/180499471")
     @Test
     public void initCecVersion_limitToMinimumSupportedVersion() {
+        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
+        Log.e("MARVIN", "set setting CEC");
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
 
-        mHdmiControlService.initService();
+        mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
     }
 
-    @Ignore("b/180499471")
     @Test
     public void initCecVersion_limitToAtLeast1_4() {
+        Log.e("MARVIN", "set HAL CEC to 0");
+        mNativeWrapper.setCecVersion(0x0);
+        Log.e("MARVIN", "set setting CEC to 2");
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mNativeWrapper.setCecVersion(0x0);
 
-        mHdmiControlService.initService();
+        mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
     }
 
-    @Ignore("b/180499471")
     @Test
     public void initCecVersion_useHighestMatchingVersion() {
+        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        Log.e("MARVIN", "set setting CEC");
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
 
-        mHdmiControlService.initService();
+        mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index b8dfd56..605f781 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -84,8 +84,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         mHdmiControlService = new HdmiControlService(mContextSpy) {
             @Override
             AudioManager getAudioManager() {
@@ -116,15 +114,11 @@
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
 
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
@@ -185,6 +179,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mTestLooper.dispatchAll();
         sendMessageFromPlaybackDevice(ADDR_PLAYBACK_1, 0x1000);
         reportPowerStatus(ADDR_PLAYBACK_1, true, HdmiControlManager.POWER_STATUS_ON);
         mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index f9160ab..e82c788 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -65,8 +65,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         HdmiControlService hdmiControlService = new HdmiControlService(context) {
                     @Override
                     void sendCecCommand(
@@ -164,15 +162,11 @@
                     int pathToPortId(int path) {
                         return -1;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
+        hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         HdmiCecController.NativeWrapper nativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 hdmiControlService, nativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index deaeb46..8b35af8 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -276,7 +276,7 @@
                 0 /* sourceUserId */, 0, "someTag",
                 invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
                 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
-                persistedExecutionTimesUTC, 0 /* innerFlagg */);
+                persistedExecutionTimesUTC, 0 /* innerFlag */, 0 /* dynamicConstraints */);
 
         mTaskStoreUnderTest.add(js);
         waitForPendingIo();
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index f87d599..7d9ab37 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -20,8 +20,10 @@
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+import static com.android.server.job.JobConcurrencyManager.workTypeToString;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -54,7 +56,7 @@
 
     private static final double[] EQUAL_PROBABILITY_CDF =
             buildWorkTypeCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES,
-                    1.0 / NUM_WORK_TYPES);
+                    1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES);
 
     private Random mRandom;
     private WorkCountTracker mWorkCountTracker;
@@ -66,8 +68,9 @@
     }
 
     @NonNull
-    private static double[] buildWorkTypeCdf(double pTop, double pEj, double pBg, double pBgUser) {
-        return buildCdf(pTop, pEj, pBg, pBgUser);
+    private static double[] buildWorkTypeCdf(
+            double pTop, double pFgs, double pEj, double pBg, double pBgUser) {
+        return buildCdf(pTop, pFgs, pEj, pBg, pBgUser);
     }
 
     @NonNull
@@ -102,10 +105,12 @@
             case 0:
                 return WORK_TYPE_TOP;
             case 1:
-                return WORK_TYPE_EJ;
+                return WORK_TYPE_FGS;
             case 2:
-                return WORK_TYPE_BG;
+                return WORK_TYPE_EJ;
             case 3:
+                return WORK_TYPE_BG;
+            case 4:
                 return WORK_TYPE_BGUSER;
             default:
                 throw new IllegalStateException("Unknown work type");
@@ -224,12 +229,15 @@
 
     private void startPendingJobs(Jobs jobs) {
         while (hasStartablePendingJob(jobs)) {
-            final int startingWorkType =
-                    getRandomWorkType(EQUAL_PROBABILITY_CDF, mRandom.nextDouble());
+            final int workType = getRandomWorkType(EQUAL_PROBABILITY_CDF, mRandom.nextDouble());
 
-            if (jobs.pending.get(startingWorkType) > 0
-                    && mWorkCountTracker.canJobStart(startingWorkType) != WORK_TYPE_NONE) {
-                final int pendingMultiType = getPendingMultiType(jobs, startingWorkType);
+            if (jobs.pending.get(workType) > 0) {
+                final int pendingMultiType = getPendingMultiType(jobs, workType);
+                final int startingWorkType = mWorkCountTracker.canJobStart(pendingMultiType);
+                if (startingWorkType == WORK_TYPE_NONE) {
+                    continue;
+                }
+
                 jobs.removePending(pendingMultiType);
                 jobs.running.put(startingWorkType, jobs.running.get(startingWorkType) + 1);
                 mWorkCountTracker.stageJob(startingWorkType, pendingMultiType);
@@ -304,7 +312,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final List<Pair<Integer, Integer>> minLimits = List.of();
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0);
+        final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0);
         final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
         final double probStart = 0.5;
 
@@ -322,7 +330,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3);
         final double[] numTypesCdf = buildCdf(.75, .2, .05);
         final double probStart = 0.5;
 
@@ -340,7 +348,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final List<Pair<Integer, Integer>> minLimits = List.of();
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3);
         final double[] numTypesCdf = buildCdf(.05, .95);
         final double probStart = 0.5;
 
@@ -358,7 +366,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0.8, .1);
+        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, .1);
         final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
         final double probStart = 0.5;
 
@@ -376,7 +384,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0.9, 0, 0.1, 0);
+        final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -394,7 +402,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0.1, .8);
+        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, .8);
         final double[] numTypesCdf = buildCdf(0.5, 0.5);
         final double probStart = 0.5;
 
@@ -413,7 +421,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.9, 0, 0.05, 0.05);
+        final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0.05);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -432,7 +440,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0, 0, 0.5, 0.5);
+        final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0.5);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -451,7 +459,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0, 0, 0.1, 0.9);
+        final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0.9);
         final double[] numTypesCdf = buildCdf(0.9, 0.1);
         final double probStart = 0.5;
 
@@ -470,7 +478,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0, 0, 0.9, 0.1);
+        final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0.1);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -488,7 +496,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.5, 0.5, 0, 0);
+        final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0);
         final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2);
         final double probStart = 0.5;
 
@@ -511,7 +519,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1));
         final double probStop = 0.13;
-        final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.85);
+        final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.8, 0.05);
         final double probStart = 0.87;
 
         checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
@@ -528,7 +536,7 @@
                 List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(.1, 0.5, 0.35, 0.05);
+        final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0.05);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -548,7 +556,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.01, 0.49, 0.1, 0.4);
+        final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0.4);
         final double[] numTypesCdf = buildCdf(0.7, 0.3);
         final double probStart = 0.5;
 
@@ -576,11 +584,13 @@
         startPendingJobs(jobs);
 
         for (Pair<Integer, Integer> run : resultRunning) {
-            assertWithMessage("Incorrect running result for work type " + run.first)
+            assertWithMessage(
+                    "Incorrect running result for work type " + workTypeToString(run.first))
                     .that(jobs.running.get(run.first)).isEqualTo(run.second);
         }
         for (Pair<Integer, Integer> pend : resultPending) {
-            assertWithMessage("Incorrect pending result for work type " + pend.first)
+            assertWithMessage(
+                    "Incorrect pending result for work type " + workTypeToString(pend.first))
                     .that(jobs.pending.get(pend.first)).isEqualTo(pend.second);
         }
     }
@@ -938,10 +948,15 @@
         assertThat(jobs.running.get(WORK_TYPE_TOP)).isEqualTo(6);
         assertThat(jobs.running.get(WORK_TYPE_EJ)).isEqualTo(1);
         assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
-        assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(4);
+        // If run the TOP jobs as TOP first, and a TOP|EJ job as EJ, then we'll have 4 TOP jobs
+        // remaining.
+        assertThat(jobs.pending.get(WORK_TYPE_TOP)).isAtLeast(4);
+        // If we end up running the TOP|EJ jobs as TOP first, then we'll have 5 TOP jobs remaining.
+        assertThat(jobs.pending.get(WORK_TYPE_TOP)).isAtMost(5);
         // Can't equate pending EJ since some could be running as TOP and BG
         assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
-        assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(9);
+        assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtLeast(8);
+        assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtMost(9);
 
         // Stop all jobs
         jobs.maybeFinishJobs(1);
@@ -975,7 +990,7 @@
         assertThat(jobs.running.get(WORK_TYPE_EJ)).isAtLeast(1);
         assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
         assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
-        assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
+        assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(1);
         assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(4);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index 2288a89..cc18317 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -18,7 +18,9 @@
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+import static com.android.server.job.JobConcurrencyManager.workTypeToString;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -44,10 +46,12 @@
 public class WorkTypeConfigTest {
     private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
     private static final String KEY_MAX_TOP = "concurrency_max_top_test";
+    private static final String KEY_MAX_FGS = "concurrency_max_fgs_test";
     private static final String KEY_MAX_EJ = "concurrency_max_ej_test";
     private static final String KEY_MAX_BG = "concurrency_max_bg_test";
     private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
     private static final String KEY_MIN_TOP = "concurrency_min_top_test";
+    private static final String KEY_MIN_FGS = "concurrency_min_fgs_test";
     private static final String KEY_MIN_EJ = "concurrency_min_ej_test";
     private static final String KEY_MIN_BG = "concurrency_min_bg_test";
     private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
@@ -59,15 +63,17 @@
 
     private void resetConfig() {
         // DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually.
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, "", false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_FGS, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_FGS, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, null, false);
     }
 
     private void check(@Nullable DeviceConfig.Properties config,
@@ -103,10 +109,12 @@
 
         assertEquals(expectedTotal, counts.getMaxTotal());
         for (Pair<Integer, Integer> min : expectedMinLimits) {
-            assertEquals((int) min.second, counts.getMinReserved(min.first));
+            assertEquals("Incorrect min value for " + workTypeToString(min.first),
+                    (int) min.second, counts.getMinReserved(min.first));
         }
         for (Pair<Integer, Integer> max : expectedMaxLimits) {
-            assertEquals((int) max.second, counts.getMax(max.first));
+            assertEquals("Incorrect max value for " + workTypeToString(max.first),
+                    (int) max.second, counts.getMax(max.first));
         }
     }
 
@@ -193,6 +201,14 @@
                 /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
                         Pair.create(WORK_TYPE_BG, 1)),
                 /* max */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)));
+        check(null, /*default*/ 10,
+                /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2),
+                        Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)),
+                /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)),
+                /*expected*/ true, 10,
+                /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2),
+                        Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)),
+                /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)));
         check(null, /*default*/ 15,
                 /* min */ List.of(Pair.create(WORK_TYPE_BG, 15)),
                 /* max */ List.of(Pair.create(WORK_TYPE_BG, 15)),
@@ -289,5 +305,30 @@
                 /*expected*/ true, 16,
                 /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 8)),
                 /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
+
+        check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+                        .setInt(KEY_MAX_TOTAL, 16)
+                        .setInt(KEY_MAX_TOP, 16)
+                        .setInt(KEY_MIN_TOP, 1)
+                        .setInt(KEY_MAX_FGS, 15)
+                        .setInt(KEY_MIN_FGS, 2)
+                        .setInt(KEY_MAX_EJ, 14)
+                        .setInt(KEY_MIN_EJ, 3)
+                        .setInt(KEY_MAX_BG, 13)
+                        .setInt(KEY_MIN_BG, 4)
+                        .setInt(KEY_MAX_BGUSER, 12)
+                        .setInt(KEY_MIN_BGUSER, 5)
+                        .build(),
+                /*default*/ 9,
+                /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+                /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+                /*expected*/ true, 16,
+                /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_FGS, 2),
+                        Pair.create(WORK_TYPE_EJ, 3),
+                        Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 5)),
+                /* max */
+                List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_FGS, 15),
+                        Pair.create(WORK_TYPE_EJ, 14),
+                        Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 12)));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 74bf4f5..13c3919 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -2041,7 +2041,8 @@
         final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
         networkCapabilities.addTransportType(TRANSPORT_WIFI);
         networkCapabilities.setSSID(TEST_SSID);
-        return new NetworkState(TYPE_WIFI, prop, networkCapabilities, null, null);
+        return new NetworkState(TYPE_WIFI, prop, networkCapabilities, new Network(TEST_NET_ID),
+                null);
     }
 
     private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index fb13d87..c2b3858 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -17,10 +17,10 @@
 package com.android.server.pm.parsing;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.apex.ApexInfo;
 import android.content.Context;
@@ -39,6 +39,7 @@
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
 import android.util.SparseIntArray;
 
 import androidx.test.InstrumentationRegistry;
@@ -50,12 +51,17 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.InputStream;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.function.Function;
 
 /**
@@ -89,6 +95,8 @@
     private static final int PLATFORM_VERSION = 20;
     private static final int NEWER_VERSION = 30;
 
+    @Rule public final Expect expect = Expect.create();
+
     private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
             boolean isPlatformReleased, int expectedMinSdk) {
         final String[] outError = new String[1];
@@ -553,36 +561,44 @@
 
     @Test
     public void testUsesSdk() throws Exception {
-        ParsedPackage pkg =
-                parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
-        SparseIntArray minExtVers = pkg.getMinExtensionVersions();
+        ParsedPackage pkg;
+        SparseIntArray minExtVers;
+        pkg = parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
+        minExtVers = pkg.getMinExtensionVersions();
         assertEquals(1, minExtVers.size());
-        assertEquals(0, minExtVers.get(10000, -1));
+        assertEquals(0, minExtVers.get(30, -1));
 
-        try {
-            parsePackage("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5, x -> x);
-            fail("Expected parsing exception due to incompatible extension SDK version");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_FAILED_OLDER_SDK, expected.error);
-        }
-        try {
-            parsePackage("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0, x -> x);
-            fail("Expected parsing exception due to non-existent extension SDK");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
-        }
-        try {
-            parsePackage("install_uses_sdk.apk_r", R.raw.install_uses_sdk_r, x -> x);
-            fail("Expected parsing exception due to unspecified extension SDK version");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
-        }
-        try {
-            parsePackage("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0, x -> x);
-            fail("Expected parsing exception due to unspecified extension SDK");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
-        }
+        pkg = parsePackage("install_uses_sdk.apk_r0_s0", R.raw.install_uses_sdk_r0_s0, x -> x);
+        minExtVers = pkg.getMinExtensionVersions();
+        assertEquals(2, minExtVers.size());
+        assertEquals(0, minExtVers.get(30, -1));
+        assertEquals(0, minExtVers.get(31, -1));
 
+        Map<Pair<String, Integer>, Integer> appToError = new HashMap<>();
+        appToError.put(Pair.create("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5),
+                       PackageManager.INSTALL_FAILED_OLDER_SDK);
+        appToError.put(Pair.create("install_uses_sdk.apk_r0_s5", R.raw.install_uses_sdk_r0_s5),
+                       PackageManager.INSTALL_FAILED_OLDER_SDK);
+
+        appToError.put(Pair.create("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+        appToError.put(Pair.create("install_uses_sdk.apk_q0_r0", R.raw.install_uses_sdk_q0_r0),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+        appToError.put(Pair.create("install_uses_sdk.apk_r_none", R.raw.install_uses_sdk_r_none),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+        appToError.put(Pair.create("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+
+        for (Map.Entry<Pair<String, Integer>, Integer> entry : appToError.entrySet()) {
+            String filename = entry.getKey().first;
+            int resId = entry.getKey().second;
+            int result = entry.getValue();
+            try {
+                parsePackage(filename, resId, x -> x);
+                expect.withMessage("Expected parsing error %d from %s", result, filename).fail();
+            } catch (PackageParser.PackageParserException expected) {
+                expect.that(expected.error).isEqualTo(result);
+            }
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 11fb002..624c3de 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -144,6 +144,9 @@
     private static final long RARE_THRESHOLD = 48 * HOUR_MS;
     private static final long RESTRICTED_THRESHOLD = 96 * HOUR_MS;
 
+    private static final int ASSERT_RETRY_ATTEMPTS = 20;
+    private static final int ASSERT_RETRY_DELAY_MILLISECONDS = 500;
+
     /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
     private static boolean isPackageInstalled = true;
 
@@ -589,16 +592,37 @@
                 mInjector.mElapsedRealtime);
     }
 
-    private void assertBucket(int bucket) {
+    private void assertBucket(int bucket) throws InterruptedException {
         assertBucket(bucket, PACKAGE_1);
     }
 
-    private void assertBucket(int bucket, String pkg) {
+    private void assertBucket(int bucket, String pkg) throws InterruptedException {
+        int retries = 0;
+        do {
+            if (bucket == getStandbyBucket(mController, pkg)) {
+                // Success
+                return;
+            }
+            Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
+            retries++;
+        } while(retries < ASSERT_RETRY_ATTEMPTS);
+        // try one last time
         assertEquals(bucket, getStandbyBucket(mController, pkg));
     }
 
-    private void assertNotBucket(int bucket) {
-        assertNotEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
+    private void assertNotBucket(int bucket) throws InterruptedException {
+        final String pkg = PACKAGE_1;
+        int retries = 0;
+        do {
+            if (bucket != getStandbyBucket(mController, pkg)) {
+                // Success
+                return;
+            }
+            Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
+            retries++;
+        } while(retries < ASSERT_RETRY_ATTEMPTS);
+        // try one last time
+        assertNotEquals(bucket, getStandbyBucket(mController, pkg));
     }
 
     @Test
@@ -996,7 +1020,7 @@
      * a low bucket after the RESTRICTED timeout.
      */
     @Test
-    public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() {
+    public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
@@ -1032,7 +1056,7 @@
      * a low bucket after the RESTRICTED timeout.
      */
     @Test
-    public void testRestrictedTimeoutOverridesPredictionLowBucket() {
+    public void testRestrictedTimeoutOverridesPredictionLowBucket() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
 
         // Not long enough to time out into RESTRICTED.
@@ -1055,7 +1079,7 @@
     }
 
     @Test
-    public void testRestrictedBucketDisabled() {
+    public void testRestrictedBucketDisabled() throws Exception {
         mInjector.mIsRestrictedBucketEnabled = false;
         // Get the controller to read the new value. Capturing the ContentObserver isn't possible
         // at the moment.
@@ -1080,7 +1104,7 @@
     }
 
     @Test
-    public void testRestrictedBucket_EnabledToDisabled() {
+    public void testRestrictedBucket_EnabledToDisabled() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
@@ -1097,7 +1121,7 @@
     }
 
     @Test
-    public void testPredictionRaiseFromRestrictedTimeout_highBucket() {
+    public void testPredictionRaiseFromRestrictedTimeout_highBucket() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
 
         // Way past all timeouts. App times out into RESTRICTED bucket.
@@ -1114,7 +1138,7 @@
     }
 
     @Test
-    public void testPredictionRaiseFromRestrictedTimeout_lowBucket() {
+    public void testPredictionRaiseFromRestrictedTimeout_lowBucket() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
 
         // Way past all timeouts. App times out into RESTRICTED bucket.
@@ -1366,7 +1390,7 @@
     }
 
     @Test
-    public void testAddActiveDeviceAdmin() {
+    public void testAddActiveDeviceAdmin() throws Exception {
         assertActiveAdmins(USER_ID, (String[]) null);
         assertActiveAdmins(USER_ID2, (String[]) null);
 
@@ -1402,7 +1426,7 @@
     }
 
     @Test
-    public void isActiveDeviceAdmin() {
+    public void isActiveDeviceAdmin() throws Exception {
         assertActiveAdmins(USER_ID, (String[]) null);
         assertActiveAdmins(USER_ID2, (String[]) null);
 
@@ -1488,7 +1512,7 @@
     }
 
     @Test
-    public void testAppUpdateOnRestrictedBucketStatus() {
+    public void testAppUpdateOnRestrictedBucketStatus() throws Exception {
         // Updates shouldn't change bucket if the app timed out.
         // Way past all timeouts. App times out into RESTRICTED bucket.
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1563,7 +1587,7 @@
     }
 
     @Test
-    public void testSystemHeadlessAppElevated() {
+    public void testSystemHeadlessAppElevated() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
                 PACKAGE_SYSTEM_HEADFULL);
@@ -1589,7 +1613,7 @@
     }
 
     @Test
-    public void testWellbeingAppElevated() {
+    public void testWellbeingAppElevated() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_WELLBEING);
         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_WELLBEING);
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index 8c62b7f..3ca9060 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -91,6 +91,7 @@
 
         mInputDeviceDelegate = new InputDeviceDelegate(
                 mContextSpy, new Handler(mTestLooper.getLooper()));
+        mInputDeviceDelegate.onSystemReady();
     }
 
     @After
@@ -99,6 +100,24 @@
     }
 
     @Test
+    public void beforeSystemReady_ignoresAnyUpdate() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
+        InputDeviceDelegate inputDeviceDelegate = new InputDeviceDelegate(
+                mContextSpy, new Handler(mTestLooper.getLooper()));
+
+        inputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertFalse(inputDeviceDelegate.isAvailable());
+
+        inputDeviceDelegate.onInputDeviceAdded(1);
+        assertFalse(inputDeviceDelegate.isAvailable());
+
+        updateInputDevices(new int[]{1});
+        assertFalse(inputDeviceDelegate.isAvailable());
+
+        verify(mIInputManagerMock, never()).getInputDevice(anyInt());
+    }
+
+    @Test
     public void onInputDeviceAdded_withSettingsDisabled_ignoresNewDevice() throws Exception {
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
         mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ false);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
index 1e6ef91..b6c11fe 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -88,6 +88,7 @@
         mVibrationSettings = new VibrationSettings(
                 mContextSpy, new Handler(mTestLooper.getLooper()));
         mVibrationScaler = new VibrationScaler(mContextSpy, mVibrationSettings);
+        mVibrationSettings.onSystemReady();
     }
 
     @After
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index d867987..85501245 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -106,6 +106,7 @@
         mAudioManager = mContextSpy.getSystemService(AudioManager.class);
         mVibrationSettings = new VibrationSettings(mContextSpy,
                 new Handler(mTestLooper.getLooper()));
+        mVibrationSettings.onSystemReady();
 
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
@@ -162,6 +163,23 @@
     }
 
     @Test
+    public void shouldVibrateForRingerMode_beforeSystemReady_returnsFalseOnlyForRingtone() {
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+        setRingerMode(AudioManager.RINGER_MODE_MAX);
+        VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
+                new Handler(mTestLooper.getLooper()));
+
+        assertFalse(vibrationSettings.shouldVibrateForRingerMode(
+                VibrationAttributes.USAGE_RINGTONE));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
+                VibrationAttributes.USAGE_NOTIFICATION));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
+                VibrationAttributes.USAGE_COMMUNICATION_REQUEST));
+    }
+
+    @Test
     public void shouldVibrateForRingerMode_withoutRingtoneUsage_returnsTrue() {
         assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM));
         assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH));
@@ -303,6 +321,37 @@
     }
 
     @Test
+    public void getDefaultIntensity_beforeSystemReady_returnsMediumToAllExceptAlarm() {
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+
+        VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
+                new Handler(mTestLooper.getLooper()));
+
+        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(
+                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+    }
+
+    @Test
     public void getDefaultIntensity_returnsIntensityFromVibratorService() {
         mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
         mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index ba0a472..a28d18f 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -176,8 +176,14 @@
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
     }
 
+    private VibratorManagerService createSystemReadyService() {
+        VibratorManagerService service = createService();
+        service.systemReady();
+        return service;
+    }
+
     private VibratorManagerService createService() {
-        VibratorManagerService service = new VibratorManagerService(
+        return new VibratorManagerService(
                 mContextSpy,
                 new VibratorManagerService.Injector() {
                     @Override
@@ -201,8 +207,6 @@
                     void addService(String name, IBinder service) {
                     }
                 });
-        service.systemReady();
-        return service;
     }
 
     @Test
@@ -215,21 +219,44 @@
     }
 
     @Test
+    public void createService_doNotCrashIfUsedBeforeSystemReady() {
+        mockVibrators(1, 2);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        VibratorManagerService service = createService();
+
+        assertNotNull(service.getVibratorIds());
+        assertNotNull(service.getVibratorInfo(1));
+        assertFalse(service.isVibrating(1));
+
+        CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
+        service.cancelVibrate(service);
+
+        assertTrue(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+
+        IVibratorStateListener listener = mockVibratorStateListener();
+        assertTrue(service.registerVibratorStateListener(1, listener));
+        assertTrue(service.unregisterVibratorStateListener(1, listener));
+    }
+
+    @Test
     public void getVibratorIds_withNullResultFromNative_returnsEmptyArray() {
         when(mNativeWrapperMock.getVibratorIds()).thenReturn(null);
-        assertArrayEquals(new int[0], createService().getVibratorIds());
+        assertArrayEquals(new int[0], createSystemReadyService().getVibratorIds());
     }
 
     @Test
     public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() {
         mockVibrators(2, 1);
-        assertArrayEquals(new int[]{2, 1}, createService().getVibratorIds());
+        assertArrayEquals(new int[]{2, 1}, createSystemReadyService().getVibratorIds());
     }
 
     @Test
     public void getVibratorInfo_withMissingVibratorId_returnsNull() {
         mockVibrators(1);
-        assertNull(createService().getVibratorInfo(2));
+        assertNull(createSystemReadyService().getVibratorInfo(2));
     }
 
     @Test
@@ -239,7 +266,7 @@
         vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL);
         vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
-        VibratorInfo info = createService().getVibratorInfo(1);
+        VibratorInfo info = createSystemReadyService().getVibratorInfo(1);
 
         assertNotNull(info);
         assertEquals(1, info.getId());
@@ -257,7 +284,7 @@
     @Test
     public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener listenerMock = mockVibratorStateListener();
         service.registerVibratorStateListener(1, listenerMock);
 
@@ -278,7 +305,7 @@
     @Test
     public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener listenerMock = mockVibratorStateListener();
         service.registerVibratorStateListener(1, listenerMock);
 
@@ -303,7 +330,7 @@
     @Test
     public void registerVibratorStateListener_multipleVibratorsAreTriggered() throws Exception {
         mockVibrators(0, 1, 2);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener[] listeners = new IVibratorStateListener[3];
         for (int i = 0; i < 3; i++) {
             listeners[i] = mockVibratorStateListener();
@@ -330,7 +357,8 @@
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         VibrationEffect.Prebaked expectedEffect = new VibrationEffect.Prebaked(
                 VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
@@ -353,7 +381,8 @@
                 .addVibrator(2, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
                 .addVibrator(3, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
                 .combine();
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         VibrationEffect.Prebaked expectedClick = new VibrationEffect.Prebaked(
                 VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
@@ -376,9 +405,11 @@
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
 
         assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
         assertNull(mVibratorProviders.get(2).getAlwaysOnEffect(1));
@@ -392,7 +423,8 @@
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
-        assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertFalse(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
@@ -405,7 +437,8 @@
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSequential()
                 .addNext(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .combine();
-        assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertFalse(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
@@ -413,7 +446,7 @@
     @Test
     public void setAlwaysOnEffect_withNoVibratorWithCapability_ignoresEffect() {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect mono = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
@@ -435,18 +468,18 @@
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         vibrate(service, VibrationEffect.createOneShot(40, 1), RINGTONE_ATTRS);
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
-        service = createService();
+        service = createSystemReadyService();
         vibrate(service, VibrationEffect.createOneShot(40, 10), RINGTONE_ATTRS);
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
-        service = createService();
+        service = createSystemReadyService();
         vibrate(service, VibrationEffect.createOneShot(40, 100), RINGTONE_ATTRS);
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
 
@@ -459,7 +492,7 @@
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
         vibrate(service, VibrationEffect.createOneShot(1, 1), HAPTIC_FEEDBACK_ATTRS);
         vibrate(service, VibrationEffect.createOneShot(2, 2), RINGTONE_ATTRS);
@@ -480,7 +513,7 @@
 
     @Test
     public void vibrate_withAudioAttributes_usesOriginalAudioUsageInAppOpsManager() {
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
         AudioAttributes audioAttributes = new AudioAttributes.Builder()
@@ -496,7 +529,7 @@
 
     @Test
     public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() {
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), NOTIFICATION_ATTRS);
@@ -534,7 +567,7 @@
         when(mIInputManagerMock.getVibratorIds(eq(1))).thenReturn(new int[]{1});
         when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createOneShot(10, 10));
@@ -550,7 +583,7 @@
     public void vibrate_withNativeCallbackTriggered_finishesVibration() throws Exception {
         mockVibrators(1);
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         // The native callback will be dispatched manually in this test.
         mTestLooper.stopAutoDispatchAndIgnoreExceptions();
 
@@ -573,7 +606,7 @@
         mockVibrators(1, 2);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         // The native callback will be dispatched manually in this test.
         mTestLooper.stopAutoDispatchAndIgnoreExceptions();
 
@@ -619,7 +652,7 @@
         FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
         fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -645,7 +678,7 @@
         mockVibrators(1, 2);
         FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
         fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -665,7 +698,7 @@
         mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_ON);
         mockVibrators(1, 2);
         when(mNativeWrapperMock.prepareSynced(any())).thenReturn(false);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.createOneShot(10, 50))
@@ -686,7 +719,7 @@
         mockVibrators(1, 2);
         when(mNativeWrapperMock.prepareSynced(eq(new int[]{1, 2}))).thenReturn(true);
         when(mNativeWrapperMock.triggerSynced(anyLong())).thenReturn(false);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.createOneShot(10, 50))
@@ -716,7 +749,7 @@
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL,
                 IVibrator.CAP_COMPOSE_EFFECTS);
         fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -762,7 +795,7 @@
     @Test
     public void vibrate_withPowerModeChange_cancelVibrationIfNotAllowed() throws Exception {
         mockVibrators(1, 2);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         vibrate(service,
                 CombinedVibrationEffect.startSynced()
                         .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
@@ -780,7 +813,7 @@
     @Test
     public void vibrate_withSettingsChange_doNotCancelVibration() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
@@ -793,7 +826,7 @@
     @Test
     public void cancelVibrate_stopsVibrating() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         service.cancelVibrate(service);
         assertFalse(service.isVibrating(1));
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
deleted file mode 100644
index 3025a95..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import static android.view.KeyEvent.ACTION_DOWN;
-import static android.view.KeyEvent.ACTION_UP;
-import static android.view.KeyEvent.KEYCODE_POWER;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test class for {@link SingleKeyGestureDetector}.
- *
- * Build/Install/Run:
- *  atest WmTests:SingleKeyGestureTests
- */
-public class SingleKeyGestureTests {
-    private SingleKeyGestureDetector mDetector;
-
-    private int mMaxMultiPressPowerCount = 2;
-
-    private CountDownLatch mShortPressed = new CountDownLatch(1);
-    private CountDownLatch mLongPressed = new CountDownLatch(1);
-    private CountDownLatch mVeryLongPressed = new CountDownLatch(1);
-    private CountDownLatch mMultiPressed = new CountDownLatch(1);
-
-    private final Instrumentation mInstrumentation = getInstrumentation();
-    private final Context mContext = mInstrumentation.getTargetContext();
-    private long mWaitTimeout;
-    private long mLongPressTime;
-    private long mVeryLongPressTime;
-
-    @Before
-    public void setUp() {
-        mDetector = new SingleKeyGestureDetector(mContext);
-        initSingleKeyGestureRules();
-        mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
-        mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
-        mVeryLongPressTime = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_veryLongPressTimeout) + 50;
-    }
-
-    private void initSingleKeyGestureRules() {
-        mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER,
-                KEY_LONGPRESS | KEY_VERYLONGPRESS) {
-            @Override
-            int getMaxMultiPressCount() {
-                return mMaxMultiPressPowerCount;
-            }
-            @Override
-            public void onPress(long downTime) {
-                mShortPressed.countDown();
-            }
-
-            @Override
-            void onLongPress(long downTime) {
-                mLongPressed.countDown();
-            }
-
-            @Override
-            void onVeryLongPress(long downTime) {
-                mVeryLongPressed.countDown();
-            }
-
-            @Override
-            void onMultiPress(long downTime, int count) {
-                mMultiPressed.countDown();
-                assertEquals(mMaxMultiPressPowerCount, count);
-            }
-        });
-    }
-
-    private void pressKey(long eventTime, int keyCode, long pressTime) {
-        final KeyEvent keyDown = new KeyEvent(eventTime, eventTime, ACTION_DOWN,
-                keyCode, 0 /* repeat */, 0 /* metaState */);
-        mDetector.interceptKey(keyDown);
-
-        // keep press down.
-        try {
-            Thread.sleep(pressTime);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-
-        eventTime += pressTime;
-        final KeyEvent keyUp = new KeyEvent(eventTime, eventTime, ACTION_UP,
-                keyCode, 0 /* repeat */, 0 /* metaState */);
-
-        mDetector.interceptKey(keyUp);
-    }
-
-    @Test
-    public void testShortPress() throws InterruptedException {
-        final long eventTime = SystemClock.uptimeMillis();
-        pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
-        assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testLongPress() throws InterruptedException {
-        final long eventTime = SystemClock.uptimeMillis();
-        pressKey(eventTime, KEYCODE_POWER, mLongPressTime);
-        assertTrue(mLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testVeryLongPress() throws InterruptedException {
-        final long eventTime = SystemClock.uptimeMillis();
-        pressKey(eventTime, KEYCODE_POWER, mVeryLongPressTime);
-        assertTrue(mVeryLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testMultiPress() throws InterruptedException {
-        final long eventTime = SystemClock.uptimeMillis();
-        pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
-        pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
-        assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 990927b..d8e7582 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1965,17 +1965,17 @@
 
         // Non-resizable
         mAtm.mForceResizableActivities = false;
-        mAtm.mSizeCompatFreeform = false;
+        mAtm.mSupportsNonResizableMultiWindow = false;
         assertFalse(activity.supportsFreeform());
 
         // Force resizable
         mAtm.mForceResizableActivities = true;
-        mAtm.mSizeCompatFreeform = false;
+        mAtm.mSupportsNonResizableMultiWindow = false;
         assertTrue(activity.supportsFreeform());
 
         // Allow non-resizable
         mAtm.mForceResizableActivities = false;
-        mAtm.mSizeCompatFreeform = true;
+        mAtm.mSupportsNonResizableMultiWindow = true;
         assertTrue(activity.supportsFreeform());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 137cf65..09a436c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -518,6 +518,7 @@
                 TYPE_WALLPAPER, TYPE_APPLICATION);
         final WindowState wallpaper = windows[0];
         assertTrue(wallpaper.mIsWallpaper);
+        wallpaper.mToken.asWallpaperToken().setVisibility(false);
         // By default WindowState#mWallpaperVisible is false.
         assertFalse(wallpaper.isVisible());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 47cf53b..074ef36 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -323,4 +323,16 @@
         assertFalse(navBarSource.getFrame().isEmpty());
         assertTrue(imeSource.getFrame().contains(navBarSource.getFrame()));
     }
+
+    @UseTestDisplay
+    @Test
+    public void testDisplayPolicyNotCrash() {
+        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+
+        // Verify if modules initialized after DisplayContent ctr throws NPE.
+        displayPolicy.onDisplayInfoChanged(mDisplayInfo);
+        displayPolicy.onConfigurationChanged();
+        displayPolicy.onOverlayChangedLw();
+        displayPolicy.release();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index be03603..80961d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -416,6 +416,16 @@
         verify(navBar, atLeastOnce()).notifyInsetsChanged();
     }
 
+    @Test
+    public void testDispatchGlobalInsets() {
+        final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+        getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        assertNull(getController().getInsetsForWindow(app).peekSource(ITYPE_NAVIGATION_BAR));
+        app.mAttrs.receiveInsetsIgnoringZOrder = true;
+        assertNotNull(getController().getInsetsForWindow(app).peekSource(ITYPE_NAVIGATION_BAR));
+    }
+
     private WindowState createTestWindow(String name) {
         final WindowState win = createWindow(null, TYPE_APPLICATION, name);
         win.setHasSurface(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index d663b64..cc1869e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -454,7 +454,7 @@
         Settings.Secure.clearProviderForTest();
 
         // AND a password is set
-        when(mLockPatternUtils.isSecure(anyInt()))
+        when(mLockPatternUtils.isSecure(TEST_USER_ID))
                 .thenReturn(true);
 
         // AND there is a task record
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 2fdd63e..ea97180 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -18,11 +18,13 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -35,7 +37,9 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 
@@ -94,7 +98,7 @@
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
         mAdapter.setCallingPidUid(123, 456);
         runWithScissors(mWm.mH, () -> mHandler = new TestHandler(null, mClock), 0);
-        mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
+        mController = new RemoteAnimationController(mWm, mDisplayContent, mAdapter, mHandler);
     }
 
     private WindowState createAppOverlayWindow() {
@@ -520,6 +524,164 @@
         }
     }
 
+    @Test
+    public void testNonAppTarget_sendNavBar() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        spyOn(policy);
+        doReturn(true).when(policy).shouldAttachNavBarToAppDuringTransition();
+
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                win.mActivityRecord, new Point(50, 100), null,
+                new Rect(50, 100, 150, 150), null).mAdapter;
+        adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                mFinishedCallback);
+        mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+        verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+                appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                finishedCaptor.capture());
+        boolean containNavTarget = false;
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                containNavTarget = true;
+                break;
+            }
+        }
+        assertTrue(containNavTarget);
+    }
+
+    @Test
+    public void testNonAppTarget_notSendNavBar_notAttachToApp() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        spyOn(policy);
+        doReturn(false).when(policy).shouldAttachNavBarToAppDuringTransition();
+
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                win.mActivityRecord, new Point(50, 100), null,
+                new Rect(50, 100, 150, 150), null).mAdapter;
+        adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                mFinishedCallback);
+        mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+        verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+                appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                finishedCaptor.capture());
+        boolean containNavTarget = false;
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                containNavTarget = true;
+                break;
+            }
+        }
+        assertFalse(containNavTarget);
+    }
+
+    @Test
+    public void testNonAppTarget_notSendNavBar_controlledByFixedRotation() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        final FixedRotationAnimationController mockController =
+                mock(FixedRotationAnimationController.class);
+        doReturn(mockController).when(mDisplayContent).getFixedRotationAnimationController();
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        spyOn(policy);
+        doReturn(true).when(policy).shouldAttachNavBarToAppDuringTransition();
+
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                win.mActivityRecord, new Point(50, 100), null,
+                new Rect(50, 100, 150, 150), null).mAdapter;
+        adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                mFinishedCallback);
+        mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+        verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+                appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                finishedCaptor.capture());
+        boolean containNavTarget = false;
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                containNavTarget = true;
+                break;
+            }
+        }
+        assertFalse(containNavTarget);
+    }
+
+    @Test
+    public void testNonAppTarget_notSendNavBar_controlledByRecents() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mOpeningApps.add(win.mActivityRecord);
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        mDisplayContent.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
+        final RecentsAnimationController mockController =
+                mock(RecentsAnimationController.class);
+        doReturn(mockController).when(mWm).getRecentsAnimationController();
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        spyOn(policy);
+        doReturn(true).when(policy).shouldAttachNavBarToAppDuringTransition();
+
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                win.mActivityRecord, new Point(50, 100), null,
+                new Rect(50, 100, 150, 150), null).mAdapter;
+        adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+                mFinishedCallback);
+        mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+        verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+                appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+                finishedCaptor.capture());
+        boolean containNavTarget = false;
+        for (int i = 0; i < nonAppsCaptor.getValue().length; i++) {
+            if (nonAppsCaptor.getValue()[0].windowType == TYPE_NAVIGATION_BAR) {
+                containNavTarget = true;
+                break;
+            }
+        }
+        assertFalse(containNavTarget);
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index f8346efb..5239462 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -473,6 +473,68 @@
                 mDefaultDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea);
     }
 
+    @Test
+    public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea() {
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+        final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
+                mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+        secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
+                        DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
+        final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+        launchRoot.mCreatedByOrganizer = true;
+        secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
+                new int[] { ACTIVITY_TYPE_STANDARD });
+        final Rect secondaryDAStableBounds = new Rect();
+        secondaryDisplayArea.getStableRect(secondaryDAStableBounds);
+
+        // Specify the display and provide a layout so that it will be set to freeform bounds.
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(freeformDisplay.getDisplayId());
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setOptions(options).setLayout(layout).calculate());
+
+        assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
+        assertTrue(secondaryDAStableBounds.contains(mResult.mBounds));
+    }
+
+    @Test
+    public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea_unresizableApp() {
+        mAtm.mSupportsNonResizableMultiWindow = true;
+
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+        final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
+                mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+        secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
+                DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
+        final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+        launchRoot.mCreatedByOrganizer = true;
+        secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
+                new int[] { ACTIVITY_TYPE_STANDARD });
+        final Rect secondaryDAStableBounds = new Rect();
+        secondaryDisplayArea.getStableRect(secondaryDAStableBounds);
+
+        // The bounds will get updated for unresizable with opposite orientation on freeform display
+        final Rect displayBounds = new Rect(freeformDisplay.getBounds());
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.screenOrientation = displayBounds.width() > displayBounds.height()
+                ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE;
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(freeformDisplay.getDisplayId());
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setOptions(options).calculate());
+
+        assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
+        assertTrue(secondaryDAStableBounds.contains(mResult.mBounds));
+    }
+
     // =====================================
     // Launch Windowing Mode Related Tests
     // =====================================
@@ -521,6 +583,7 @@
                 WINDOWING_MODE_FULLSCREEN);
     }
 
+
     @Test
     public void testKeepsPictureInPictureLaunchModeInOptions() {
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
@@ -588,11 +651,14 @@
     }
 
     @Test
-    public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
+    public void testLayoutWithGravityAndEmptySizeInfersFreeformAndRespectsCurrentSize() {
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
+        final Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
+
         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+        mCurrent.mBounds.set(expectedLaunchBounds);
 
         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
                 .setGravity(Gravity.LEFT).build();
@@ -600,6 +666,9 @@
         assertEquals(RESULT_CONTINUE,
                 new CalculateRequestBuilder().setLayout(layout).calculate());
 
+        assertEquals(expectedLaunchBounds.width(), mResult.mBounds.width());
+        assertEquals(expectedLaunchBounds.height(), mResult.mBounds.height());
+
         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
                 WINDOWING_MODE_FREEFORM);
     }
@@ -661,7 +730,7 @@
 
     @Test
     public void testForceMaximizesUnresizeableApp() {
-        mAtm.mSizeCompatFreeform = false;
+        mAtm.mSupportsNonResizableMultiWindow = false;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
@@ -684,7 +753,7 @@
 
     @Test
     public void testLaunchesPortraitSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
-        mAtm.mSizeCompatFreeform = true;
+        mAtm.mSupportsNonResizableMultiWindow = true;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
@@ -712,7 +781,7 @@
 
     @Test
     public void testLaunchesLandscapeSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
-        mAtm.mSizeCompatFreeform = true;
+        mAtm.mSupportsNonResizableMultiWindow = true;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -728,7 +797,7 @@
 
     @Test
     public void testLaunchesPortraitUnresizableOnFreeformDisplayWithFreeformSizeCompat() {
-        mAtm.mSizeCompatFreeform = true;
+        mAtm.mSupportsNonResizableMultiWindow = true;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
         final ActivityOptions options = ActivityOptions.makeBasic();
@@ -1358,8 +1427,8 @@
         // This test case requires a relatively big app bounds to ensure the default size calculated
         // by letterbox won't be too small to hold the minimum width/height.
         configInsetsState(
-                freeformDisplay.getInsetsStateController().getRawInsetsState(),
-                DISPLAY_BOUNDS, new Rect(10, 10, 1910, 1070));
+                freeformDisplay.getInsetsStateController().getRawInsetsState(), freeformDisplay,
+                new Rect(10, 10, 1910, 1070));
 
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
@@ -1580,15 +1649,17 @@
         display.setBounds(DISPLAY_BOUNDS);
         display.getConfiguration().densityDpi = DENSITY_DEFAULT;
         display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
-        configInsetsState(display.getInsetsStateController().getRawInsetsState(),
-                DISPLAY_BOUNDS, DISPLAY_STABLE_BOUNDS);
+        configInsetsState(display.getInsetsStateController().getRawInsetsState(), display,
+                DISPLAY_STABLE_BOUNDS);
         return display;
     }
 
     /**
      * Creates insets sources so that we can get the expected stable frame.
      */
-    private static void configInsetsState(InsetsState state, Rect displayFrame, Rect stableFrame) {
+    private static void configInsetsState(InsetsState state, DisplayContent display,
+            Rect stableFrame) {
+        final Rect displayFrame = display.getBounds();
         final int dl = displayFrame.left;
         final int dt = displayFrame.top;
         final int dr = displayFrame.right;
@@ -1611,6 +1682,8 @@
         if (sb < db) {
             state.getSource(ITYPE_NAVIGATION_BAR).setFrame(dl, sb, dr, db);
         }
+        // Recompute config and push to children.
+        display.onRequestedOverrideConfigurationChanged(display.getConfiguration());
     }
 
     private ActivityRecord createSourceActivity(TestDisplayContent display) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 401ace03c..154a899 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -316,9 +316,9 @@
                 mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */));
         final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
                 "wallpaperWindow");
-        wallpaperWindow.mWallpaperVisible = false;
+        wallpaperWindowToken.setVisibleRequested(false);
         transition.collect(wallpaperWindowToken);
-        wallpaperWindow.mWallpaperVisible = true;
+        wallpaperWindowToken.setVisibleRequested(true);
         wallpaperWindow.mHasSurface = true;
 
         // doesn't matter which order collected since participants is a set
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index d1d0ac6..8b4e947 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -24,6 +24,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -49,7 +51,9 @@
 import android.view.InsetsState;
 import android.view.RoundedCorners;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.window.ITransitionPlayer;
 
 import androidx.test.filters.SmallTest;
 
@@ -135,7 +139,8 @@
         int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight));
 
         // Check that the wallpaper is correctly scaled
-        assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrame());
+        assertEquals(expectedWidth, wallpaperWindow.getFrame().width());
+        assertEquals(displayHeight, wallpaperWindow.getFrame().height());
         Rect portraitFrame = wallpaperWindow.getFrame();
 
         // Rotate the display
@@ -297,6 +302,46 @@
         assertFalse(mAppWindow.mActivityRecord.hasFixedRotationTransform());
     }
 
+    @Test
+    public void testWallpaperTokenVisibility() {
+        final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+        final WallpaperWindowToken token = new WallpaperWindowToken(mWm, mock(IBinder.class),
+                true, dc, true /* ownerCanManageAppTokens */);
+        final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, token,
+                "wallpaperWindow");
+        wallpaperWindow.setHasSurface(true);
+
+        // Set-up mock shell transitions
+        final IBinder mockBinder = mock(IBinder.class);
+        final ITransitionPlayer mockPlayer = mock(ITransitionPlayer.class);
+        doReturn(mockBinder).when(mockPlayer).asBinder();
+        mWm.mAtmService.getTransitionController().registerTransitionPlayer(mockPlayer);
+
+        Transition transit =
+                mWm.mAtmService.getTransitionController().createTransition(TRANSIT_OPEN);
+
+        // wallpaper windows are immediately visible when set to visible even during a transition
+        token.setVisibility(true);
+        assertTrue(wallpaperWindow.isVisible());
+        assertTrue(token.isVisibleRequested());
+        assertTrue(token.isVisible());
+        mWm.mAtmService.getTransitionController().abort(transit);
+
+        // In a transition, setting invisible should ONLY set requestedVisible false; otherwise
+        // wallpaper should remain "visible" until transition is over.
+        transit = mWm.mAtmService.getTransitionController().createTransition(TRANSIT_CLOSE);
+        transit.start();
+        token.setVisibility(false);
+        assertTrue(wallpaperWindow.isVisible());
+        assertFalse(token.isVisibleRequested());
+        assertTrue(token.isVisible());
+
+        transit.onTransactionReady(transit.getSyncId(), mock(SurfaceControl.Transaction.class));
+        transit.finishTransition();
+        assertFalse(wallpaperWindow.isVisible());
+        assertFalse(token.isVisible());
+    }
+
     private WindowState createWallpaperTargetWindow(DisplayContent dc) {
         final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
                 .setTask(dc.getDefaultTaskDisplayArea().getRootHomeTask())
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 99c96bd..bbb885eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -984,6 +984,22 @@
     }
 
     @Test
+    public void testFreezeInsets() {
+        final Task stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent, stack);
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+
+        // Set visibility to false, verify the main window of the task will be set the frozen
+        // insets state immediately.
+        activity.setVisibility(false);
+        assertNotNull(win.getFrozenInsetsState());
+
+        // Now make it visible again, verify that the insets are immediately unfrozen.
+        activity.setVisibility(true);
+        assertNull(win.getFrozenInsetsState());
+    }
+
+    @Test
     public void testFreezeInsetsStateWhenAppTransition() {
         final Task stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
@@ -996,15 +1012,20 @@
         sources.add(activity);
 
         // Simulate the task applying the exit transition, verify the main window of the task
-        // will be set the frozen insets state.
+        // will be set the frozen insets state before the animation starts
+        activity.setVisibility(false);
         task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
                 false /* isVoiceInteraction */, sources);
         verify(win).freezeInsetsState();
 
-        // Simulate the task transition finished, verify the frozen insets state of the window
-        // will be reset.
+        // Simulate the task transition finished.
+        activity.commitVisibility(false, false);
         task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
                 task.mSurfaceAnimator.getAnimation());
+
+        // Now make it visible again, verify that the insets are immediately unfrozen even before
+        // transition starts.
+        activity.setVisibility(true);
         verify(win).clearFrozenInsetsState();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 0dd8d23..18c8cf5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -18,7 +18,6 @@
 
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
@@ -119,20 +118,6 @@
     }
 
     @Test
-    public void testEnableSizeCompatFreeform() {
-        try (BoolSettingsSession enableSizeCompatFreeformSession = new
-                BoolSettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
-            final boolean enableSizeCompatFreeform =
-                    !enableSizeCompatFreeformSession.getSetting();
-            final Uri enableSizeCompatFreeformUri =
-                    enableSizeCompatFreeformSession.setSetting(enableSizeCompatFreeform);
-            mWm.mSettingsObserver.onChange(false, enableSizeCompatFreeformUri);
-
-            assertEquals(mWm.mAtmService.mSizeCompatFreeform, enableSizeCompatFreeform);
-        }
-    }
-
-    @Test
     public void testSupportsNonResizableMultiWindow() {
         try (BoolSettingsSession supportsNonResizableMultiWindowSession = new
                 BoolSettingsSession(DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index c13d6b1..1f38f46 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -245,6 +245,9 @@
 
     private WindowToken createWindowToken(
             DisplayContent dc, int windowingMode, int activityType, int type) {
+        if (type == TYPE_WALLPAPER) {
+            return createWallpaperToken(dc);
+        }
         if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
             return createTestWindowToken(type, dc);
         }
@@ -252,6 +255,11 @@
         return createActivityRecord(dc, windowingMode, activityType);
     }
 
+    private WindowToken createWallpaperToken(DisplayContent dc) {
+        return new WallpaperWindowToken(mWm, mock(IBinder.class), true /* explicit */, dc,
+                true /* ownerCanManageAppTokens */);
+    }
+
     WindowState createAppWindow(Task task, int type, String name) {
         final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
         task.addChild(activity, 0);
@@ -538,9 +546,8 @@
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
     private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) {
-        final DisplayContent display =
+        final DisplayContent dc =
                 new TestDisplayContent.Builder(mAtm, info).build();
-        final DisplayContent dc = display.mDisplayContent;
         // this display can show IME.
         dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
         return dc;
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 6aadd23..8874e0a 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -20,19 +20,29 @@
 import static android.content.Context.TRANSLATION_MANAGER_SERVICE;
 import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
 import android.view.translation.ITranslationManager;
 import android.view.translation.TranslationSpec;
 import android.view.translation.UiTranslationManager.UiTranslationState;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.List;
 
 /**
@@ -48,6 +58,8 @@
 
     private static final String TAG = "TranslationManagerService";
 
+    private static final int MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS = 2 * 60_000; // 2 minutes
+
     public TranslationManagerService(Context context) {
         // TODO: Discuss the disallow policy
         super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -60,19 +72,82 @@
         return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled);
     }
 
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_UI_TRANSLATION, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS;
+    }
+
+    @Override
+    protected void dumpLocked(String prefix, PrintWriter pw) {
+        super.dumpLocked(prefix, pw);
+    }
+
     private void enforceCallerHasPermission(String permission) {
         final String msg = "Permission Denial from pid =" + Binder.getCallingPid() + ", uid="
                 + Binder.getCallingUid() + " doesn't hold " + permission;
         getContext().enforceCallingPermission(permission, msg);
     }
 
+    /** True if the currently set handler service is not overridden by the shell. */
+    @GuardedBy("mLock")
+    private boolean isDefaultServiceLocked(int userId) {
+        final String defaultServiceName = mServiceNameResolver.getDefaultServiceName(userId);
+        if (defaultServiceName == null) {
+            return false;
+        }
+
+        final String currentServiceName = mServiceNameResolver.getServiceName(userId);
+        return defaultServiceName.equals(currentServiceName);
+    }
+
+    /** True if the caller of the api is the same app which hosts the TranslationService. */
+    @GuardedBy("mLock")
+    private boolean isCalledByServiceAppLocked(int userId, @NonNull String methodName) {
+        final int callingUid = Binder.getCallingUid();
+
+        final String serviceName = mServiceNameResolver.getServiceName(userId);
+        if (serviceName == null) {
+            Slog.e(TAG, methodName + ": called by UID " + callingUid
+                    + ", but there's no service set for user " + userId);
+            return false;
+        }
+
+        final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+        if (serviceComponent == null) {
+            Slog.w(TAG, methodName + ": invalid service name: " + serviceName);
+            return false;
+        }
+
+        final String servicePackageName = serviceComponent.getPackageName();
+        final PackageManager pm = getContext().getPackageManager();
+        final int serviceUid;
+        try {
+            serviceUid = pm.getPackageUidAsUser(servicePackageName, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, methodName + ": could not verify UID for " + serviceName);
+            return false;
+        }
+        if (callingUid != serviceUid) {
+            Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is "
+                    + serviceUid);
+            return false;
+        }
+        return true;
+    }
+
     final class TranslationManagerServiceStub extends ITranslationManager.Stub {
         @Override
         public void getSupportedLocales(IResultReceiver receiver, int userId)
                 throws RemoteException {
             synchronized (mLock) {
                 final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId, "getSupportedLocales"))) {
                     service.getSupportedLocalesLocked(receiver);
                 } else {
                     Slog.v(TAG, "getSupportedLocales(): no service for " + userId);
@@ -86,7 +161,8 @@
                 int sessionId, IResultReceiver receiver, int userId) throws RemoteException {
             synchronized (mLock) {
                 final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId, "onSessionCreated"))) {
                     service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver);
                 } else {
                     Slog.v(TAG, "onSessionCreated(): no service for " + userId);
@@ -96,18 +172,58 @@
         }
 
         @Override
-        public void updateUiTranslationState(@UiTranslationState int state,
+        public void updateUiTranslationStateByTaskId(@UiTranslationState int state,
                 TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
                 int taskId, int userId) {
+            // deprecated
             enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
             synchronized (mLock) {
                 final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
-                    service.updateUiTranslationState(state, sourceSpec, destSpec, viewIds,
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId,
+                        "updateUiTranslationStateByTaskId"))) {
+                    service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
                             taskId);
                 }
             }
         }
+
+        @Override
+        public void updateUiTranslationState(@UiTranslationState int state,
+                TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
+                IBinder token, int taskId, int userId) {
+            enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
+            synchronized (mLock) {
+                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) {
+                    service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
+                            token, taskId);
+                }
+            }
+        }
+
+        /**
+         * Dump the service state into the given stream. You run "adb shell dumpsys translation".
+        */
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            synchronized (mLock) {
+                dumpLocked("", pw);
+            }
+        }
+
+        @Override
+        public void onShellCommand(@Nullable FileDescriptor in,
+                @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args,
+                @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            new TranslationManagerServiceShellCommand(
+                    TranslationManagerService.this).exec(this, in, out, err, args, callback,
+                    resultReceiver);
+        }
     }
 
     @Override // from SystemService
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 38be85c..ab6ac12 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.translation.TranslationServiceInfo;
 import android.util.Slog;
@@ -133,18 +134,40 @@
     }
 
     @GuardedBy("mLock")
-    public void updateUiTranslationState(@UiTranslationState int state,
+    public void updateUiTranslationStateLocked(@UiTranslationState int state,
             TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
             int taskId) {
-        // TODO(b/177394471): use taskId as a temporary solution. The solution may use a token to
-        //  content capture manager service find the activitytoken. Then we can use this
-        //  activitytoken to find the activity to callback. But we need to change cc API so use
-        //  temporary solution.
-        final ActivityTokens tokens = mActivityTaskManagerInternal.getTopActivityForTask(taskId);
-        if (tokens == null) {
+        // deprecated
+        final ActivityTokens taskTopActivityTokens =
+                mActivityTaskManagerInternal.getTopActivityForTask(taskId);
+        if (taskTopActivityTokens == null) {
             Slog.w(TAG, "Unknown activity to query for update translation state.");
             return;
         }
+        updateUiTranslationStateByActivityTokens(taskTopActivityTokens, state, sourceSpec, destSpec,
+                viewIds);
+    }
+
+    @GuardedBy("mLock")
+    public void updateUiTranslationStateLocked(@UiTranslationState int state,
+            TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
+            IBinder token, int taskId) {
+        // Get top activity for a given task id
+        final ActivityTokens taskTopActivityTokens =
+                mActivityTaskManagerInternal.getTopActivityForTask(taskId);
+        if (taskTopActivityTokens == null
+                || taskTopActivityTokens.getShareableActivityToken() != token) {
+            Slog.w(TAG, "Unknown activity or it was finished to query for update "
+                    + "translation state for token=" + token + " taskId=" + taskId);
+            return;
+        }
+        updateUiTranslationStateByActivityTokens(taskTopActivityTokens, state, sourceSpec, destSpec,
+                viewIds);
+    }
+
+    private void updateUiTranslationStateByActivityTokens(ActivityTokens tokens,
+            @UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec destSpec,
+            List<AutofillId> viewIds) {
         try {
             tokens.getApplicationThread().updateUiTranslationState(tokens.getActivityToken(), state,
                     sourceSpec, destSpec, viewIds);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java
new file mode 100644
index 0000000..ba1b390
--- /dev/null
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.translation;
+
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/** Handles adb shell commands send to TranslationManagerService. */
+public class TranslationManagerServiceShellCommand extends ShellCommand {
+    private final TranslationManagerService mService;
+
+    TranslationManagerServiceShellCommand(TranslationManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        if ("set".equals(cmd)) {
+            return requestSet(pw);
+        }
+        return handleDefaultCommands(cmd);
+    }
+
+    private int requestSet(PrintWriter pw) {
+        final String what = getNextArgRequired();
+        if ("temporary-service".equals(what)) {
+            return setTemporaryService(pw);
+        }
+        pw.println("Invalid set: " + what);
+        return -1;
+    }
+
+    private int setTemporaryService(PrintWriter pw) {
+        final int userId = Integer.parseInt(getNextArgRequired());
+        final String serviceName = getNextArg();
+        if (serviceName == null) {
+            mService.resetTemporaryService(userId);
+            return 0;
+        }
+        final int duration = Integer.parseInt(getNextArgRequired());
+        mService.setTemporaryService(userId, serviceName, duration);
+        pw.println("TranslationService temporarily set to " + serviceName + " for "
+                + duration + "ms");
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter();) {
+            pw.println("Translation Service (translation) commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implementation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b1e6683..f35b9e2 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -303,7 +303,9 @@
                 // FLUSH_TO_DISK is a private event.
                 && event.mEventType != Event.FLUSH_TO_DISK
                 // DEVICE_SHUTDOWN is added to event list after reboot.
-                && event.mEventType != Event.DEVICE_SHUTDOWN) {
+                && event.mEventType != Event.DEVICE_SHUTDOWN
+                // We aren't interested in every instance of the APP_COMPONENT_USED event.
+                && event.mEventType != Event.APP_COMPONENT_USED) {
             currentDailyStats.addEvent(event);
         }
 
@@ -1176,6 +1178,8 @@
                 return "USER_STOPPED";
             case Event.LOCUS_ID_SET:
                 return "LOCUS_ID_SET";
+            case Event.APP_COMPONENT_USED:
+                return "APP_COMPONENT_USED";
             default:
                 return "UNKNOWN_TYPE_" + eventType;
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 35e65c1..ed71d17 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -22,25 +22,49 @@
 import android.content.Intent;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
+import android.media.AudioAttributes;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.service.voice.AlwaysOnHotwordDetector;
 import android.service.voice.HotwordDetectionService;
 import android.service.voice.IDspHotwordDetectionCallback;
 import android.service.voice.IHotwordDetectionService;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.infra.ServiceConnector;
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A class that provides the communication with the HotwordDetectionService.
  */
 final class HotwordDetectionConnection {
-    static final String TAG = "HotwordDetectionConnection";
+    private static final String TAG = "HotwordDetectionConnection";
     // TODO (b/177502877): Set the Debug flag to false before shipping.
-    static final boolean DEBUG = true;
+    private static final boolean DEBUG = true;
+
+    // Number of bytes per sample of audio (which is a short).
+    private static final int BYTES_PER_SAMPLE = 2;
+    // TODO: These constants need to be refined.
+    private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
+    private static final long VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS = 2000;
+    private static final int MAX_STREAMING_SECONDS = 10;
+
+    private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
+    // TODO: This may need to be a Handler(looper)
+    private final ScheduledExecutorService mScheduledExecutorService =
+            Executors.newSingleThreadScheduledExecutor();
 
     final Object mLock;
     final ComponentName mDetectionComponentName;
@@ -93,42 +117,106 @@
         }
     }
 
-    private void detectFromDspSource(int sessionId, IDspHotwordDetectionCallback callback) {
+    private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
+            IHotwordRecognitionStatusCallback externalCallback) {
         if (DEBUG) {
             Slog.d(TAG, "detectFromDspSource");
         }
+
+        AudioRecord record = createAudioRecord(recognitionEvent);
+
+        Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
+
+        if (clientPipe == null) {
+            // Error.
+            // Need to propagate as unknown error or something?
+            return;
+        }
+        ParcelFileDescriptor audioSink = clientPipe.second;
+        ParcelFileDescriptor clientRead = clientPipe.first;
+
+        record.startRecording();
+
+        mAudioCopyExecutor.execute(() -> {
+            try (OutputStream fos =
+                         new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) {
+                byte[] buffer = new byte[1024];
+
+                while (true) {
+                    int bytesRead = record.read(buffer, 0, 1024);
+
+                    if (bytesRead < 0) {
+                        break;
+                    }
+
+                    fos.write(buffer, 0, bytesRead);
+                }
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed supplying audio data to validator", e);
+            }
+        });
+
+        Runnable cancellingJob = () -> {
+            record.stop();
+            bestEffortCloseFileDescriptor(audioSink);
+            // TODO: consider calling externalCallback.onRejected(ERROR_TIMEOUT).
+        };
+
+        ScheduledFuture<?> cancelingFuture =
+                mScheduledExecutorService.schedule(
+                        cancellingJob, VALIDATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+        // TODO: consider making this a non-anonymous class.
+        IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
+            @Override
+            public void onDetected() throws RemoteException {
+                if (DEBUG) {
+                    Slog.d(TAG, "onDetected");
+                }
+                bestEffortCloseFileDescriptor(audioSink);
+                cancelingFuture.cancel(true);
+
+                // Give 2 more seconds for the interactor to start consuming the mic. If it fails to
+                // do so under the given time, we'll force-close the mic to make sure resources are
+                // freed up.
+                // TODO: consider modelling these 2 seconds in the API.
+                mScheduledExecutorService.schedule(
+                        cancellingJob,
+                        VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS,
+                        TimeUnit.MILLISECONDS);
+
+                externalCallback.onKeyphraseDetected(recognitionEvent);
+            }
+
+            @Override
+            public void onRejected() throws RemoteException {
+                if (DEBUG) {
+                    Slog.d(TAG, "onRejected");
+                }
+                cancelingFuture.cancel(true);
+                externalCallback.onRejected(
+                        AlwaysOnHotwordDetector.HOTWORD_DETECTION_FALSE_ALERT);
+            }
+        };
+
         mRemoteHotwordDetectionService.run(
-                service -> service.detectFromDspSource(sessionId, callback));
+                service -> service.detectFromDspSource(
+                        clientRead,
+                        recognitionEvent.getCaptureFormat(),
+                        VALIDATION_TIMEOUT_MILLIS,
+                        internalCallback));
+        bestEffortCloseFileDescriptor(clientRead);
     }
 
     static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
         private SoundTrigger.KeyphraseRecognitionEvent mRecognitionEvent;
         private final HotwordDetectionConnection mHotwordDetectionConnection;
         private final IHotwordRecognitionStatusCallback mExternalCallback;
-        private final IDspHotwordDetectionCallback mInternalCallback;
 
         SoundTriggerCallback(IHotwordRecognitionStatusCallback callback,
                 HotwordDetectionConnection connection) {
             mHotwordDetectionConnection = connection;
             mExternalCallback = callback;
-            mInternalCallback = new IDspHotwordDetectionCallback.Stub() {
-                @Override
-                public void onDetected() throws RemoteException {
-                    if (DEBUG) {
-                        Slog.d(TAG, "onDetected");
-                    }
-                    mExternalCallback.onKeyphraseDetected(mRecognitionEvent);
-                }
-
-                @Override
-                public void onRejected() throws RemoteException {
-                    if (DEBUG) {
-                        Slog.d(TAG, "onRejected");
-                    }
-                    mExternalCallback.onRejected(
-                            AlwaysOnHotwordDetector.HOTWORD_DETECTION_FALSE_ALERT);
-                }
-            };
         }
 
         @Override
@@ -142,7 +230,7 @@
             if (useHotwordDetectionService) {
                 mRecognitionEvent = recognitionEvent;
                 mHotwordDetectionConnection.detectFromDspSource(
-                        recognitionEvent.getCaptureSession(), mInternalCallback);
+                        recognitionEvent, mExternalCallback);
             } else {
                 mExternalCallback.onKeyphraseDetected(recognitionEvent);
             }
@@ -171,6 +259,48 @@
         }
     }
 
+    // TODO: figure out if we need to let the client configure some of the parameters.
+    private static AudioRecord createAudioRecord(
+            @NonNull SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) {
+        int sampleRate = recognitionEvent.getCaptureFormat().getSampleRate();
+        return new AudioRecord(
+                new AudioAttributes.Builder()
+                        .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(),
+                recognitionEvent.getCaptureFormat(),
+                getBufferSizeInBytes(sampleRate, MAX_STREAMING_SECONDS),
+                recognitionEvent.getCaptureSession());
+    }
+
+    /**
+     * Returns the number of bytes required to store {@code bufferLengthSeconds} of audio sampled at
+     * {@code sampleRate} Hz, using the format returned by DSP audio capture.
+     */
+    private static int getBufferSizeInBytes(int sampleRate, int bufferLengthSeconds) {
+        return BYTES_PER_SAMPLE * sampleRate * bufferLengthSeconds;
+    }
+
+    private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() {
+        ParcelFileDescriptor[] fileDescriptors;
+        try {
+            fileDescriptors = ParcelFileDescriptor.createPipe();
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to create audio stream pipe", e);
+            return null;
+        }
+
+        return Pair.create(fileDescriptors[0], fileDescriptors[1]);
+    }
+
+    private static void bestEffortCloseFileDescriptor(ParcelFileDescriptor fd) {
+        try {
+            fd.close();
+        } catch (IOException e) {
+            if (DEBUG) {
+                Slog.w(TAG, "Failed closing file descriptor", e);
+            }
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mBound="); pw.println(mBound);
     }
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/telecomm/java/android/telecom/BluetoothCallQualityReport.aidl
similarity index 72%
copy from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
copy to telecomm/java/android/telecom/BluetoothCallQualityReport.aidl
index ddb5ef8..685fe9c 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/telecomm/java/android/telecom/BluetoothCallQualityReport.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2021, 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
+ *     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,
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
-package android.content.pm.verify.domain;
+package android.telecom;
 
-parcelable DomainVerificationUserSelection;
+/**
+ * {@hide}
+ */
+parcelable BluetoothCallQualityReport;
diff --git a/telecomm/java/android/telecom/BluetoothCallQualityReport.java b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
index 10339a8..8703d84 100644
--- a/telecomm/java/android/telecom/BluetoothCallQualityReport.java
+++ b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
@@ -24,6 +24,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * This class represents the quality report that bluetooth framework sends
  * whenever there's a bad voice quality is detected from their side.
@@ -145,6 +147,26 @@
                 }
             };
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        BluetoothCallQualityReport that = (BluetoothCallQualityReport) o;
+        return mSentTimestampMillis == that.mSentTimestampMillis
+                && mChoppyVoice == that.mChoppyVoice && mRssiDbm == that.mRssiDbm
+                && mSnrDb == that.mSnrDb
+                && mRetransmittedPacketsCount == that.mRetransmittedPacketsCount
+                && mPacketsNotReceivedCount == that.mPacketsNotReceivedCount
+                && mNegativeAcknowledgementCount == that.mNegativeAcknowledgementCount;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSentTimestampMillis, mChoppyVoice, mRssiDbm, mSnrDb,
+                mRetransmittedPacketsCount, mPacketsNotReceivedCount,
+                mNegativeAcknowledgementCount);
+    }
+
     /**
      * Builder class for {@link ConnectionRequest}
      */
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 044ea80..2a5ddfd 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -267,6 +267,64 @@
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
 
+    /**
+     * Event reported from the Telecom stack to report an in-call diagnostic message which the
+     * dialer app may opt to display to the user.  A diagnostic message is used to communicate
+     * scenarios the device has detected which may impact the quality of the ongoing call.
+     * <p>
+     * For example a problem with a bluetooth headset may generate a recommendation for the user to
+     * try using the speakerphone instead, or if the device detects it has entered a poor service
+     * area, the user might be warned so that they can finish their call prior to it dropping.
+     * <p>
+     * A diagnostic message is considered persistent in nature.  When the user enters a poor service
+     * area, for example, the accompanying diagnostic message persists until they leave the area
+     * of poor service.  Each message is accompanied with a {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID}
+     * which uniquely identifies the diagnostic condition being reported.  The framework raises a
+     * call event of type {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE} when the condition reported has
+     * been cleared.  The dialer app should display the diagnostic message until it is cleared.
+     * If multiple diagnostic messages are sent with different IDs (which have not yet been cleared)
+     * the dialer app should prioritize the most recently received message, but still provide the
+     * user with a means to review past messages.
+     * <p>
+     * The text of the message is found in {@link #EXTRA_DIAGNOSTIC_MESSAGE} in the form of a human
+     * readable {@link CharSequence} which is intended for display in the call UX.
+     * <p>
+     * The telecom framework audibly notifies the user of the presence of a diagnostic message, so
+     * the dialer app needs only to concern itself with visually displaying the message.
+     * <p>
+     * The dialer app receives this event via
+     * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+     */
+    public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE =
+            "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE";
+
+    /**
+     * Event reported from the telecom framework when a diagnostic message previously raised with
+     * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE} has cleared and is no longer pertinent.
+     * <p>
+     * The {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} indicates the diagnostic message which has been
+     * cleared.
+     * <p>
+     * The dialer app receives this event via
+     * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+     */
+    public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE =
+            "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE";
+
+    /**
+     * Integer extra representing a message ID for a message posted via
+     * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}.  Used to ensure that the dialer app knows when
+     * the message in question has cleared via {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE}.
+     */
+    public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID =
+            "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID";
+
+    /**
+     * {@link CharSequence} extra used with {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}.  This is the
+     * diagnostic message the dialer app should display.
+     */
+    public static final String EXTRA_DIAGNOSTIC_MESSAGE =
+            "android.telecom.extra.DIAGNOSTIC_MESSAGE";
 
     /**
      * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
new file mode 100644
index 0000000..201c5db
--- /dev/null
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+
+import com.android.internal.telecom.ICallDiagnosticService;
+import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
+
+import java.util.Map;
+
+/**
+ * The platform supports a single OEM provided {@link CallDiagnosticService}, as defined by the
+ * {@code call_diagnostic_service_package_name} key in the
+ * {@code packages/services/Telecomm/res/values/config.xml} file.  An OEM can use this API to help
+ * provide more actionable information about calling issues the user encounters during and after
+ * a call.
+ *
+ * <h1>Manifest Declaration</h1>
+ * The following is an example of how to declare the service entry in the
+ * {@link CallDiagnosticService} manifest file:
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourCallDiagnosticServiceImplementation"
+ *          android:permission="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telecom.CallDiagnosticService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ * @hide
+ */
+@SystemApi
+public abstract class CallDiagnosticService extends Service {
+
+    /**
+     * Binder stub implementation which handles incoming requests from Telecom.
+     */
+    private final class CallDiagnosticServiceBinder extends ICallDiagnosticService.Stub {
+
+        @Override
+        public void setAdapter(ICallDiagnosticServiceAdapter adapter) throws RemoteException {
+            handleSetAdapter(adapter);
+        }
+
+        @Override
+        public void initializeDiagnosticCall(ParcelableCall call) throws RemoteException {
+            handleCallAdded(call);
+        }
+
+        @Override
+        public void updateCall(ParcelableCall call) throws RemoteException {
+            handleCallUpdated(call);
+        }
+
+        @Override
+        public void removeDiagnosticCall(String callId) throws RemoteException {
+            handleCallRemoved(callId);
+        }
+
+        @Override
+        public void updateCallAudioState(CallAudioState callAudioState) throws RemoteException {
+            onCallAudioStateChanged(callAudioState);
+        }
+
+        @Override
+        public void receiveDeviceToDeviceMessage(String callId, int message, int value) {
+            handleReceivedD2DMessage(callId, message, value);
+        }
+
+        @Override
+        public void receiveBluetoothCallQualityReport(BluetoothCallQualityReport qualityReport)
+                throws RemoteException {
+            handleBluetoothCallQualityReport(qualityReport);
+        }
+    }
+
+    /**
+     * Listens to events raised by a {@link DiagnosticCall}.
+     */
+    private android.telecom.DiagnosticCall.Listener mDiagnosticCallListener =
+            new android.telecom.DiagnosticCall.Listener() {
+
+                @Override
+                public void onSendDeviceToDeviceMessage(DiagnosticCall diagnosticCall,
+                        @DiagnosticCall.MessageType int message, int value) {
+                    handleSendDeviceToDeviceMessage(diagnosticCall, message, value);
+                }
+
+                @Override
+                public void onDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId,
+                        CharSequence message) {
+                    handleDisplayDiagnosticMessage(diagnosticCall, messageId, message);
+                }
+
+                @Override
+                public void onClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId) {
+                    handleClearDiagnosticMessage(diagnosticCall, messageId);
+                }
+            };
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecom.CallDiagnosticService";
+
+    /**
+     * Map which tracks the Telecom calls received from the Telecom stack.
+     */
+    private final Map<String, Call.Details> mCallByTelecomCallId = new ArrayMap<>();
+    private final Map<String, DiagnosticCall> mDiagnosticCallByTelecomCallId = new ArrayMap<>();
+    private ICallDiagnosticServiceAdapter mAdapter;
+
+    @Nullable
+    @Override
+    public IBinder onBind(@NonNull Intent intent) {
+        Log.i(this, "onBind!");
+        return new CallDiagnosticServiceBinder();
+    }
+
+    /**
+     * Telecom calls this method on the {@link CallDiagnosticService} with details about a new call
+     * which was added to Telecom.
+     * <p>
+     * The {@link CallDiagnosticService} returns an implementation of {@link DiagnosticCall} to be
+     * used for the lifespan of this call.
+     *
+     * @param call The details of the new call.
+     * @return An instance of {@link DiagnosticCall} which the {@link CallDiagnosticService}
+     * provides to be used for the lifespan of the call.
+     * @throws IllegalArgumentException if a {@code null} {@link DiagnosticCall} is returned.
+     */
+    public abstract @NonNull DiagnosticCall onInitializeDiagnosticCall(@NonNull
+            android.telecom.Call.Details call);
+
+    /**
+     * Telecom calls this method when a previous created {@link DiagnosticCall} is no longer needed.
+     * This happens when Telecom is no longer tracking the call in question.
+     * @param call The diagnostic call which is no longer tracked by Telecom.
+     */
+    public abstract void onRemoveDiagnosticCall(@NonNull DiagnosticCall call);
+
+    /**
+     * Telecom calls this method when the audio routing or available audio route information
+     * changes.
+     * <p>
+     * Audio state is common to all calls.
+     *
+     * @param audioState The new audio state.
+     */
+    public abstract void onCallAudioStateChanged(
+            @NonNull CallAudioState audioState);
+
+    /**
+     * Telecom calls this method when a {@link BluetoothCallQualityReport} is received from the
+     * bluetooth stack.
+     * @param qualityReport the {@link BluetoothCallQualityReport}.
+     */
+    public abstract void onBluetoothCallQualityReportReceived(
+            @NonNull BluetoothCallQualityReport qualityReport);
+
+    /**
+     * Handles a request from Telecom to set the adapater used to communicate back to Telecom.
+     * @param adapter
+     */
+    private void handleSetAdapter(@NonNull ICallDiagnosticServiceAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Handles a request from Telecom to add a new call.
+     * @param parcelableCall
+     */
+    private void handleCallAdded(@NonNull ParcelableCall parcelableCall) {
+        String telecomCallId = parcelableCall.getId();
+        Log.i(this, "handleCallAdded: callId=%s - added", telecomCallId);
+        Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall);
+        mCallByTelecomCallId.put(telecomCallId, newCallDetails);
+
+        DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails);
+        if (diagnosticCall == null) {
+            throw new IllegalArgumentException("A valid DiagnosticCall instance was not provided.");
+        }
+        diagnosticCall.setListener(mDiagnosticCallListener);
+        diagnosticCall.setCallId(telecomCallId);
+        mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall);
+    }
+
+    /**
+     * Handles an update to {@link Call.Details} notified by Telecom.
+     * Caches the call details and notifies the {@link DiagnosticCall} of the change via
+     * {@link DiagnosticCall#onCallDetailsChanged(Call.Details)}.
+     * @param parcelableCall the new parceled call details from Telecom.
+     */
+    private void handleCallUpdated(@NonNull ParcelableCall parcelableCall) {
+        String telecomCallId = parcelableCall.getId();
+        Log.i(this, "handleCallUpdated: callId=%s - updated", telecomCallId);
+        Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall);
+
+        DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId);
+        mCallByTelecomCallId.put(telecomCallId, newCallDetails);
+        diagnosticCall.handleCallUpdated(newCallDetails);
+    }
+
+    /**
+     * Handles a request from Telecom to remove an existing call.
+     * @param telecomCallId
+     */
+    private void handleCallRemoved(@NonNull String telecomCallId) {
+        Log.i(this, "handleCallRemoved: callId=%s - removed", telecomCallId);
+
+        if (mCallByTelecomCallId.containsKey(telecomCallId)) {
+            mCallByTelecomCallId.remove(telecomCallId);
+        }
+        if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) {
+            DiagnosticCall call = mDiagnosticCallByTelecomCallId.remove(telecomCallId);
+            // Inform the service of the removed call.
+            onRemoveDiagnosticCall(call);
+        }
+    }
+
+    /**
+     * Handles an incoming device to device message received from Telecom.  Notifies the
+     * {@link DiagnosticCall} via {@link DiagnosticCall#onReceiveDeviceToDeviceMessage(int, int)}.
+     * @param callId
+     * @param message
+     * @param value
+     */
+    private void handleReceivedD2DMessage(@NonNull String callId, int message, int value) {
+        Log.i(this, "handleReceivedD2DMessage: callId=%s, msg=%d/%d", callId, message, value);
+        DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId);
+        diagnosticCall.onReceiveDeviceToDeviceMessage(message, value);
+    }
+
+    /**
+     * Handles an incoming bluetooth call quality report from Telecom.  Notifies via
+     * {@link CallDiagnosticService#onBluetoothCallQualityReportReceived(
+     * BluetoothCallQualityReport)}.
+     * @param qualityReport The bluetooth call quality remote.
+     */
+    private void handleBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport
+            qualityReport) {
+        Log.i(this, "handleBluetoothCallQualityReport; report=%s", qualityReport);
+        onBluetoothCallQualityReportReceived(qualityReport);
+    }
+
+    /**
+     * Handles a request from a {@link DiagnosticCall} to send a device to device message (received
+     * via {@link DiagnosticCall#sendDeviceToDeviceMessage(int, int)}.
+     * @param diagnosticCall
+     * @param message
+     * @param value
+     */
+    private void handleSendDeviceToDeviceMessage(@NonNull DiagnosticCall diagnosticCall,
+            int message, int value) {
+        String callId = diagnosticCall.getCallId();
+        try {
+            mAdapter.sendDeviceToDeviceMessage(callId, message, value);
+            Log.i(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d", callId, message,
+                    value);
+        } catch (RemoteException e) {
+            Log.w(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d failed %s",
+                    callId, message, value, e);
+        }
+    }
+
+    /**
+     * Handles a request from a {@link DiagnosticCall} to display an in-call diagnostic message.
+     * Originates from {@link DiagnosticCall#displayDiagnosticMessage(int, CharSequence)}.
+     * @param diagnosticCall
+     * @param messageId
+     * @param message
+     */
+    private void handleDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId,
+            CharSequence message) {
+        String callId = diagnosticCall.getCallId();
+        try {
+            mAdapter.displayDiagnosticMessage(callId, messageId, message);
+            Log.i(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s", callId, messageId,
+                    message);
+        } catch (RemoteException e) {
+            Log.w(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s failed %s",
+                    callId, messageId, message, e);
+        }
+    }
+
+    /**
+     * Handles a request from a {@link DiagnosticCall} to clear a previously shown diagnostic
+     * message.
+     * Originates from {@link DiagnosticCall#clearDiagnosticMessage(int)}.
+     * @param diagnosticCall
+     * @param messageId
+     */
+    private void handleClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId) {
+        String callId = diagnosticCall.getCallId();
+        try {
+            mAdapter.clearDiagnosticMessage(callId, messageId);
+            Log.i(this, "handleClearDiagnosticMessage: call=%s; msg=%d", callId, messageId);
+        } catch (RemoteException e) {
+            Log.w(this, "handleClearDiagnosticMessage: call=%s; msg=%d failed %s",
+                    callId, messageId, e);
+        }
+    }
+}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7c6253ce..335857af8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -938,6 +938,46 @@
     public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED =
             "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
 
+    /**
+     * Connection event used to signal between the telephony {@link ConnectionService} and Telecom
+     * when device to device messages are sent/received.
+     * <p>
+     * Device to device messages originating from the network are sent by telephony using
+     * {@link Connection#sendConnectionEvent(String, Bundle)} and are routed up to any active
+     * {@link CallDiagnosticService} implementation which is active.
+     * <p>
+     * Likewise, if a {@link CallDiagnosticService} sends a message using
+     * {@link DiagnosticCall#sendDeviceToDeviceMessage(int, int)}, it will be routed to telephony
+     * via {@link Connection#onCallEvent(String, Bundle)}.  The telephony stack will relay the
+     * message to the other device.
+     * @hide
+     */
+    @SystemApi
+    public static final String EVENT_DEVICE_TO_DEVICE_MESSAGE =
+            "android.telecom.event.DEVICE_TO_DEVICE_MESSAGE";
+
+    /**
+     * Sent along with {@link #EVENT_DEVICE_TO_DEVICE_MESSAGE} to indicate the device to device
+     * message type.
+     *
+     * See {@link DiagnosticCall} for more information.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE =
+            "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_TYPE";
+
+    /**
+     * Sent along with {@link #EVENT_DEVICE_TO_DEVICE_MESSAGE} to indicate the device to device
+     * message value.
+     * <p>
+     * See {@link DiagnosticCall} for more information.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE =
+            "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
diff --git a/telecomm/java/android/telecom/DiagnosticCall.java b/telecomm/java/android/telecom/DiagnosticCall.java
new file mode 100644
index 0000000..a495289
--- /dev/null
+++ b/telecomm/java/android/telecom/DiagnosticCall.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.telephony.Annotation;
+import android.telephony.CallQuality;
+import android.telephony.ims.ImsReasonInfo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A {@link DiagnosticCall} provides a way for a {@link CallDiagnosticService} to receive diagnostic
+ * information about a mobile call on the device.  The {@link CallDiagnosticService} can generate
+ * mid-call diagnostic messages using the {@link #displayDiagnosticMessage(int, CharSequence)} API
+ * which provides the user with valuable information about conditions impacting their call and
+ * corrective actions.  For example, if the {@link CallDiagnosticService} determines that conditions
+ * on the call are degrading, it can inform the user that the call may soon drop and that they
+ * can try using a different calling method (e.g. VOIP or WIFI).
+ * @hide
+ */
+@SystemApi
+public abstract class DiagnosticCall {
+
+    /**
+     * @hide
+     */
+    public interface Listener {
+        void onSendDeviceToDeviceMessage(DiagnosticCall diagnosticCall, int message, int value);
+        void onDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId,
+                CharSequence message);
+        void onClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId);
+    }
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type
+     * used for the current call.  Based loosely on the
+     * {@link android.telephony.TelephonyManager#getNetworkType(int)} for the call, provides a
+     * high level summary of the call radio access type.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #NETWORK_TYPE_LTE}</LI>
+     *     <LI>{@link #NETWORK_TYPE_IWLAN}</LI>
+     *     <LI>{@link #NETWORK_TYPE_NR}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_CALL_NETWORK_TYPE = 1;
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec
+     * used for the current call.  Based loosely on the {@link Connection#EXTRA_AUDIO_CODEC} for a
+     * call.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #AUDIO_CODEC_EVS}</LI>
+     *     <LI>{@link #AUDIO_CODEC_AMR_WB}</LI>
+     *     <LI>{@link #AUDIO_CODEC_AMR_NB}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_CALL_AUDIO_CODEC = 2;
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the battery state of
+     * the device.  Will typically mirror battery state reported via intents such as
+     * {@link android.content.Intent#ACTION_BATTERY_LOW}.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #BATTERY_STATE_LOW}</LI>
+     *     <LI>{@link #BATTERY_STATE_GOOD}</LI>
+     *     <LI>{@link #BATTERY_STATE_CHARGING}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_DEVICE_BATTERY_STATE = 3;
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the overall network
+     * coverage as it pertains to the current call.  A {@link CallDiagnosticService} should signal
+     * poor coverage if the network coverage reaches a level where there is a high probability of
+     * the call dropping as a result.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #COVERAGE_POOR}</LI>
+     *     <LI>{@link #COVERAGE_GOOD}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4;
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "MESSAGE_", value = {
+            MESSAGE_CALL_NETWORK_TYPE,
+            MESSAGE_CALL_AUDIO_CODEC,
+            MESSAGE_DEVICE_BATTERY_STATE,
+            MESSAGE_DEVICE_NETWORK_COVERAGE
+    })
+    public @interface MessageType {}
+
+    /**
+     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate an LTE network is being used for the
+     * call.
+     */
+    public static final int NETWORK_TYPE_LTE = 1;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate WIFI calling is in use for the call.
+     */
+    public static final int NETWORK_TYPE_IWLAN = 2;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate a 5G NR (new radio) network is in
+     * used for the call.
+     */
+    public static final int NETWORK_TYPE_NR = 3;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the
+     * Enhanced Voice Services (EVS) codec for the call.
+     */
+    public static final int AUDIO_CODEC_EVS = 1;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR
+     * (adaptive multi-rate) WB (wide band) audio codec.
+     */
+    public static final int AUDIO_CODEC_AMR_WB = 2;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR
+     * (adaptive multi-rate) NB (narrow band) audio codec.
+     */
+    public static final int AUDIO_CODEC_AMR_NB = 3;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low.
+     */
+    public static final int BATTERY_STATE_LOW = 1;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is not low.
+     */
+    public static final int BATTERY_STATE_GOOD = 2;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is charging.
+     */
+    public static final int BATTERY_STATE_CHARGING = 3;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is poor.
+     */
+    public static final int COVERAGE_POOR = 1;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is good.
+     */
+    public static final int COVERAGE_GOOD = 2;
+
+    private Listener mListener;
+    private String mCallId;
+    private Call.Details mCallDetails;
+
+    /**
+     * @hide
+     */
+    public void setListener(@NonNull Listener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Sets the call ID for this {@link DiagnosticCall}.
+     * @param callId
+     * @hide
+     */
+    public void setCallId(@NonNull String callId) {
+        mCallId = callId;
+    }
+
+    /**
+     * @return the Telecom call ID for this {@link DiagnosticCall}.
+     * @hide
+     */
+    public @NonNull String getCallId() {
+        return mCallId;
+    }
+
+    /**
+     * Returns the latest {@link Call.Details} associated with this {@link DiagnosticCall} as
+     * reported by {@link #onCallDetailsChanged(Call.Details)}.
+     * @return The latest {@link Call.Details}.
+     */
+    public @NonNull Call.Details getCallDetails() {
+        return mCallDetails;
+    }
+
+    /**
+     * Telecom calls this method when the details of a call changes.
+     */
+    public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details);
+
+    /**
+     * The {@link CallDiagnosticService} implements this method to handle messages received via
+     * device to device communication.
+     * <p>
+     * See {@link #sendDeviceToDeviceMessage(int, int)} for background on device to device
+     * communication.
+     * <p>
+     * The underlying device to device communication protocol assumes that where there the two
+     * devices communicating are using a different version of the protocol, messages the recipient
+     * are not aware of are silently discarded.  This means an older client talking to a new client
+     * will not receive newer messages and values sent by the new client.
+     */
+    public abstract void onReceiveDeviceToDeviceMessage(
+            @MessageType int message,
+            int value);
+
+    /**
+     * Sends a device to device message to the device on the other end of this call.
+     * <p>
+     * Device to device communication is an Android platform feature which supports low bandwidth
+     * communication between Android devices while they are in a call.  The device to device
+     * communication leverages DTMF tones or RTP header extensions to pass messages.  The
+     * messages are unacknowledged and sent in a best-effort manner.  The protocols assume that the
+     * nature of the message are informational only and are used only to convey basic state
+     * information between devices.
+     * <p>
+     * Device to device messages are intentional simplifications of more rich indicators in the
+     * platform due to the extreme bandwidth constraints inherent with underlying device to device
+     * communication transports used by the telephony framework.  Device to device communication is
+     * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets
+     * for a call, or using the DTMF digits A-D as a communication pathway.  Signalling requirements
+     * for DTMF digits place a significant limitation on the amount of information which can be
+     * communicated during a call.
+     * <p>
+     * Allowed message types and values are:
+     * <ul>
+     *     <li>{@link #MESSAGE_CALL_NETWORK_TYPE}
+     *         <ul>
+     *             <li>{@link #NETWORK_TYPE_LTE}</li>
+     *             <li>{@link #NETWORK_TYPE_IWLAN}</li>
+     *             <li>{@link #NETWORK_TYPE_NR}</li>
+     *         </ul>
+     *     </li>
+     *     <li>{@link #MESSAGE_CALL_AUDIO_CODEC}
+     *         <ul>
+     *             <li>{@link #AUDIO_CODEC_EVS}</li>
+     *             <li>{@link #AUDIO_CODEC_AMR_WB}</li>
+     *             <li>{@link #AUDIO_CODEC_AMR_NB}</li>
+     *         </ul>
+     *     </li>
+     *     <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}
+     *         <ul>
+     *             <li>{@link #BATTERY_STATE_LOW}</li>
+     *             <li>{@link #BATTERY_STATE_GOOD}</li>
+     *             <li>{@link #BATTERY_STATE_CHARGING}</li>
+     *         </ul>
+     *     </li>
+     *     <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}
+     *         <ul>
+     *             <li>{@link #COVERAGE_POOR}</li>
+     *             <li>{@link #COVERAGE_GOOD}</li>
+     *         </ul>
+     *     </li>
+     * </ul>
+     * @param message The message type to send.
+     * @param value The message value corresponding to the type.
+     */
+    public final void sendDeviceToDeviceMessage(int message, int value) {
+        if (mListener != null) {
+            mListener.onSendDeviceToDeviceMessage(this, message, value);
+        }
+    }
+
+    /**
+     * Telecom calls this method when a GSM or CDMA call disconnects.
+     * The CallDiagnosticService can return a human readable disconnect message which will be passed
+     * to the Dialer app as the {@link DisconnectCause#getDescription()}.  A dialer app typically
+     * shows this message at the termination of the call.  If {@code null} is returned, the
+     * disconnect message generated by the telephony stack will be shown instead.
+     * <p>
+     * @param disconnectCause the disconnect cause for the call.
+     * @param preciseDisconnectCause the precise disconnect cause for the call.
+     * @return the disconnect message to use in place of the default Telephony message, or
+     * {@code null} if the default message will not be overridden.
+     */
+    // TODO: Wire in Telephony support for this.
+    public abstract @Nullable CharSequence onCallDisconnected(
+            @Annotation.DisconnectCauses int disconnectCause,
+            @Annotation.PreciseDisconnectCauses int preciseDisconnectCause);
+
+    /**
+     * Telecom calls this method when an IMS call disconnects and Telephony has already
+     * provided the disconnect reason info and disconnect message for the call.  The
+     * {@link CallDiagnosticService} can intercept the raw IMS disconnect reason at this point and
+     * combine it with other call diagnostic information it is aware of to override the disconnect
+     * call message if desired.
+     *
+     * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection.
+     * @return A user-readable call disconnect message to use in place of the platform-generated
+     * disconnect message, or {@code null} if the disconnect message should not be overridden.
+     */
+    // TODO: Wire in Telephony support for this.
+    public abstract @Nullable CharSequence onCallDisconnected(
+            @NonNull ImsReasonInfo disconnectReason);
+
+    /**
+     * Telecom calls this method when a {@link CallQuality} report is received from the telephony
+     * stack for a call.
+     * @param callQuality The call quality report for this call.
+     */
+    public abstract void onCallQualityReceived(@NonNull CallQuality callQuality);
+
+     /**
+      * Signals the active default dialer app to display a call diagnostic message.  This can be
+      * used to report problems encountered during the span of a call.
+      * <p>
+      * The {@link CallDiagnosticService} provides a unique client-specific identifier used to
+      * identify the specific diagnostic message type.
+      * <p>
+      * The {@link CallDiagnosticService} should call {@link #clearDiagnosticMessage(int)} when the
+      * diagnostic condition has cleared.
+      * @param messageId the unique message identifier.
+      * @param message a human-readable, localized message to be shown to the user indicating a
+      *                call issue which has occurred, along with potential mitigating actions.
+     */
+    public final void displayDiagnosticMessage(int messageId, @NonNull
+            CharSequence message) {
+        if (mListener != null) {
+            mListener.onDisplayDiagnosticMessage(this, messageId, message);
+        }
+    }
+
+    /**
+     * Signals to the active default dialer that the diagnostic message previously signalled using
+     * {@link #displayDiagnosticMessage(int, CharSequence)} with the specified messageId is no
+     * longer applicable (e.g. service has improved, for example.
+     * @param messageId the message identifier for a message previously shown via
+     *                  {@link #displayDiagnosticMessage(int, CharSequence)}.
+     */
+    public final void clearDiagnosticMessage(int messageId) {
+        if (mListener != null) {
+            mListener.onClearDiagnosticMessage(this, messageId);
+        }
+    }
+
+    /**
+     * Called by the {@link CallDiagnosticService} to update the call details for this
+     * {@link DiagnosticCall} based on an update received from Telecom.
+     * @param newDetails the new call details.
+     * @hide
+     */
+    public void handleCallUpdated(@NonNull Call.Details newDetails) {
+        mCallDetails = newDetails;
+        onCallDetailsChanged(newDetails);
+    }
+}
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 2a4fdcb..922eddb 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -522,7 +522,7 @@
             return "";
         }
         return Arrays.stream(packageName.split("\\."))
-                .map(s -> s.substring(0,1))
+                .map(s -> s.length() == 0 ? "" : s.substring(0, 1))
                 .collect(Collectors.joining(""));
     }
 }
diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
new file mode 100644
index 0000000..65b4d19
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import android.telecom.BluetoothCallQualityReport;
+import android.telecom.CallAudioState;
+import android.telecom.ParcelableCall;
+import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
+
+/**
+ * Internal remote interface for a call diagnostic service.
+ * @see android.telecom.CallDiagnosticService
+ * @hide
+ */
+oneway interface ICallDiagnosticService {
+    void setAdapter(in ICallDiagnosticServiceAdapter adapter);
+    void initializeDiagnosticCall(in ParcelableCall call);
+    void updateCall(in ParcelableCall call);
+    void updateCallAudioState(in CallAudioState callAudioState);
+    void removeDiagnosticCall(in String callId);
+    void receiveDeviceToDeviceMessage(in String callId, int message, int value);
+    void receiveBluetoothCallQualityReport(in BluetoothCallQualityReport qualityReport);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticServiceAdapter.aidl
new file mode 100644
index 0000000..92eec2a
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticServiceAdapter.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import android.telecom.CallAudioState;
+import android.telecom.ParcelableCall;
+
+/**
+ * Remote interface for messages from the CallDiagnosticService to the platform.
+ * @see android.telecom.CallDiagnosticService
+ * @hide
+ */
+oneway interface ICallDiagnosticServiceAdapter {
+    void displayDiagnosticMessage(in String callId, int messageId, in CharSequence message);
+    void clearDiagnosticMessage(in String callId, int messageId);
+    void sendDeviceToDeviceMessage(in String callId, int message, int value);
+    void overrideDisconnectMessage(in String callId, in CharSequence message);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index eb106b5..78283fa 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -353,4 +353,8 @@
      */
     void setTestDefaultDialer(in String packageName);
 
+    /**
+     * @see TelecomServiceImpl#setTestCallDiagnosticService
+     */
+    void setTestCallDiagnosticService(in String packageName);
 }
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 706e3cb..a78f813 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -371,6 +371,7 @@
      * Get the 5G NR connection state.
      *
      * @return the 5G NR connection state.
+     * @hide
      */
     public @NRState int getNrState() {
         return mNrState;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1473b7a..cf4e677 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -891,6 +891,14 @@
     public static final String PROFILE_CLASS = SimInfo.COLUMN_PROFILE_CLASS;
 
     /**
+     * TelephonyProvider column name for VoIMS opt-in status.
+     *
+     * <P>Type: INTEGER (int)</P>
+     * @hide
+     */
+    public static final String VOIMS_OPT_IN_STATUS = SimInfo.COLUMN_VOIMS_OPT_IN_STATUS;
+
+    /**
      * Profile class of the subscription
      * @hide
      */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 61e809b..b46440d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9129,18 +9129,11 @@
      */
     public static final int CALL_COMPOSER_STATUS_ON = 1;
 
-    /**
-     * Call composer status indicating that sending/receiving pictures is disabled.
-     * All other attachments are still enabled in this state.
-     */
-    public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2;
-
     /** @hide */
     @IntDef(prefix = {"CALL_COMPOSER_STATUS_"},
             value = {
                 CALL_COMPOSER_STATUS_ON,
                 CALL_COMPOSER_STATUS_OFF,
-                CALL_COMPOSER_STATUS_ON_NO_PICTURES,
             })
     public @interface CallComposerStatus {}
 
@@ -9148,9 +9141,8 @@
      * Set the user-set status for enriched calling with call composer.
      *
      * @param status user-set status for enriched calling with call composer;
-     *               it must be any of {@link #CALL_COMPOSER_STATUS_ON}
-     *               {@link #CALL_COMPOSER_STATUS_OFF},
-     *               or {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}
+     *               it must be either {@link #CALL_COMPOSER_STATUS_ON} or
+     *               {@link #CALL_COMPOSER_STATUS_OFF}.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -9160,7 +9152,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setCallComposerStatus(@CallComposerStatus int status) {
-        if (status > CALL_COMPOSER_STATUS_ON_NO_PICTURES
+        if (status > CALL_COMPOSER_STATUS_ON
                 || status < CALL_COMPOSER_STATUS_OFF) {
             throw new IllegalArgumentException("requested status is invalid");
         }
@@ -9183,9 +9175,8 @@
      *
      * @throws SecurityException if the caller does not have the permission.
      *
-     * @return the user-set status for enriched calling with call composer, any of
-     * {@link #CALL_COMPOSER_STATUS_ON}, {@link #CALL_COMPOSER_STATUS_OFF}, or
-     * {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}.
+     * @return the user-set status for enriched calling with call composer, either of
+     * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @CallComposerStatus int getCallComposerStatus() {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 6fda2e1..0ab679f 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -866,6 +866,19 @@
     public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67;
 
     /**
+     * An integer key representing the voice over IMS opt-in provisioning status for the
+     * associated subscription. Determines whether the user can see for voice services over
+     * IMS.
+     * <p>
+     * Use {@link #PROVISIONING_VALUE_ENABLED} to enable VoIMS provisioning and
+     * {@link #PROVISIONING_VALUE_DISABLED} to disable VoIMS  provisioning.
+     * @see #setProvisioningIntValue(int, int)
+     * @see #getProvisioningIntValue(int)
+     * @hide
+     */
+    public static final int KEY_VOIMS_OPT_IN_STATUS = 68;
+
+    /**
      * Callback for IMS provisioning changes.
      */
     public static class Callback {
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index bdf628b..cedf48b 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -24,9 +24,14 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -39,6 +44,8 @@
 @SystemApi
 public final class RcsContactPresenceTuple implements Parcelable {
 
+    private static final String LOG_TAG = "RcsContactPresenceTuple";
+
     /**
      * The service ID used to indicate that service discovery via presence is available.
      * <p>
@@ -370,7 +377,8 @@
         }
 
         /**
-         * The optional SIP Contact URI associated with the PIDF tuple element.
+         * The optional SIP Contact URI associated with the PIDF tuple element if the network
+         * expects the user to use the URI instead of the contact URI to contact it.
          */
         public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
             mPresenceTuple.mContactUri = contactUri;
@@ -381,8 +389,24 @@
          * The optional timestamp indicating the data and time of the status change of this tuple.
          * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
          * string per RFC3339.
+         * @hide
          */
         public @NonNull Builder setTimestamp(@NonNull String timestamp) {
+            try {
+                mPresenceTuple.mTimestamp =
+                        DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from);
+            } catch (DateTimeParseException e) {
+                Log.d(LOG_TAG, "Parse timestamp failed " + e);
+            }
+            return this;
+        }
+
+        /**
+         * The optional timestamp indicating the data and time of the status change of this tuple.
+         * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
+         * string per RFC3339.
+         */
+        public @NonNull Builder setTime(@NonNull Instant timestamp) {
             mPresenceTuple.mTimestamp = timestamp;
             return this;
         }
@@ -414,7 +438,7 @@
     }
 
     private Uri mContactUri;
-    private String mTimestamp;
+    private Instant mTimestamp;
     private @BasicStatus String mStatus;
 
     // The service information in the service-description element.
@@ -433,7 +457,7 @@
 
     private RcsContactPresenceTuple(Parcel in) {
         mContactUri = in.readParcelable(Uri.class.getClassLoader());
-        mTimestamp = in.readString();
+        mTimestamp = convertStringFormatTimeToInstant(in.readString());
         mStatus = in.readString();
         mServiceId = in.readString();
         mServiceVersion = in.readString();
@@ -444,7 +468,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeParcelable(mContactUri, flags);
-        out.writeString(mTimestamp);
+        out.writeString(convertInstantToStringFormat(mTimestamp));
         out.writeString(mStatus);
         out.writeString(mServiceId);
         out.writeString(mServiceVersion);
@@ -470,6 +494,26 @@
                 }
             };
 
+    // Convert the Instant to the string format
+    private String convertInstantToStringFormat(Instant instant) {
+        if (instant == null) {
+            return "";
+        }
+        return instant.toString();
+    }
+
+    // Convert the time string format to Instant
+    private @Nullable Instant convertStringFormatTimeToInstant(String timestamp) {
+        if (TextUtils.isEmpty(timestamp)) {
+            return null;
+        }
+        try {
+            return DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(timestamp, Instant::from);
+        } catch (DateTimeParseException e) {
+            return null;
+        }
+    }
+
     /** @return the status of the tuple element. */
     public @NonNull @BasicStatus String getStatus() {
         return mStatus;
@@ -490,8 +534,16 @@
         return mContactUri;
     }
 
-    /** @return the timestamp element contained in the tuple if it exists */
+    /**
+     * @return the timestamp element contained in the tuple if it exists
+     * @hide
+     */
     public @Nullable String getTimestamp() {
+        return (mTimestamp == null) ? null : mTimestamp.toString();
+    }
+
+    /** @return the timestamp element contained in the tuple if it exists */
+    public @Nullable Instant getTime() {
         return mTimestamp;
     }
 
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 9299fed..52d0f03 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -340,6 +340,7 @@
     }
 
     /**
+     * Retrieve the contact URI requested by the applications.
      * @return the URI representing the contact associated with the capabilities.
      */
     public @NonNull Uri getContactUri() {
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 09c07d3..815c08d 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -32,11 +32,12 @@
 import android.telephony.ims.aidl.IImsRcsController;
 import android.telephony.ims.aidl.IRcsUceControllerCallback;
 import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
-import android.telephony.ims.feature.RcsFeature;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -431,13 +432,15 @@
 
         /**
          * The pending request has completed successfully due to all requested contacts information
-         * being delivered.
+         * being delivered. The callback {@link #onCapabilitiesReceived(List)}
+         * for each contacts is required to be called before {@link #onComplete} is called.
          */
         void onComplete();
 
         /**
          * The pending request has resulted in an error and may need to be retried, depending on the
-         * error code.
+         * error code. The callback {@link #onCapabilitiesReceived(List)}
+         * for each contacts is required to be called before {@link #onError} is called.
          * @param errorCode The reason for the framework being unable to process the request.
          * @param retryIntervalMillis The time in milliseconds the requesting application should
          * wait before retrying, if non-zero.
@@ -484,7 +487,6 @@
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
-    @SystemApi
     @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
             Manifest.permission.READ_CONTACTS})
     public void requestCapabilities(@NonNull List<Uri> contactNumbers,
@@ -550,6 +552,94 @@
     }
 
     /**
+     * Request the User Capability Exchange capabilities for one or more contacts.
+     * <p>
+     * This will return the cached capabilities of the contact and will not perform a capability
+     * poll on the network unless there are contacts being queried with stale information.
+     * <p>
+     * Be sure to check the availability of this feature using
+     * {@link ImsRcsManager#isAvailable(int, int)} and ensuring
+     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or
+     * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
+     * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
+     *
+     * @param contactNumbers A list of numbers that the capabilities are being requested for.
+     * @param executor The executor that will be used when the request is completed and the
+     *         {@link CapabilitiesCallback} is called.
+     * @param c A one-time callback for when the request for capabilities completes or there is an
+     *         error processing the request.
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE,
+            Manifest.permission.READ_CONTACTS})
+    public void requestCapabilities(@NonNull Collection<Uri> contactNumbers,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull CapabilitiesCallback c) throws ImsException {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        if (contactNumbers == null) {
+            throw new IllegalArgumentException("Must include non-null contact number list.");
+        }
+
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "requestCapabilities: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
+            }
+            @Override
+            public void onComplete() {
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> c.onComplete());
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
+            }
+            @Override
+            public void onError(int errorCode, long retryAfterMilliseconds) {
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> c.onError(errorCode, retryAfterMilliseconds));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
+            }
+        };
+
+        try {
+            imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
+                    mContext.getAttributionTag(), new ArrayList(contactNumbers), internalCallback);
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.toString(), e.errorCode);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
+    /**
      * Ignore the device cache and perform a capability discovery for one contact, also called
      * "availability fetch."
      * <p>
@@ -570,6 +660,10 @@
      * {@link CapabilitiesCallback} is called.
      * @param c A one-time callback for when the request for capabilities completes or there is
      * an error processing the request.
+     * @throws ImsException if the subscription associated with this instance of
+     * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
+     * available. This can happen if the ImsService has crashed, for example, or if the subscription
+     * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
      */
     @SystemApi
diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
index 5eee389..1b5e560 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
@@ -47,4 +47,6 @@
     void removeRcsConfigCallback(IRcsConfigCallback c);
     void triggerRcsReconfiguration();
     void setRcsClientConfiguration(in RcsClientConfiguration rcc);
+    void notifyIntImsConfigChanged(int item, int value);
+    void notifyStringImsConfigChanged(int item, String value);
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 34984e0..21aeb64 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -258,6 +258,16 @@
         public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
             getImsConfigImpl().setRcsClientConfiguration(rcc);
         }
+
+        @Override
+        public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
+            notifyImsConfigChanged(item, value);
+        }
+
+        @Override
+        public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
+            notifyImsConfigChanged(item, value);
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 908869b..00c9168 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -31,6 +31,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -241,7 +242,7 @@
 
         /**
          * Notify the framework of the response to the SUBSCRIBE request from
-         * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)}.
+         * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)}.
          * <p>
          * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
          * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
@@ -266,7 +267,7 @@
 
         /**
          * Notify the framework  of the response to the SUBSCRIBE request from
-         * {@link #subscribeForCapabilities(List, SubscribeResponseCallback)} that also
+         * {@link #subscribeForCapabilities(Collection, SubscribeResponseCallback)} that also
          * includes a reason provided in the “reason” header. See RFC3326 for more
          * information.
          *
@@ -388,6 +389,7 @@
      * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
      * capabilities for.
      * @param cb The callback of the subscribe request.
+     * @hide
      */
     // executor used is defined in the constructor.
     @SuppressLint("ExecutorRegistration")
@@ -403,6 +405,40 @@
     }
 
     /**
+     * The user capabilities of one or multiple contacts have been requested by the framework.
+     * <p>
+     * The implementer must follow up this call with an
+     * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed.
+     * The response from the network to the SUBSCRIBE request must be sent back to the framework
+     * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}.
+     * As NOTIFY requests come in from the network, the requested contact’s capabilities should be
+     * sent back to the framework using
+     * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and
+     * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)}
+     * should be called with the presence information for the contacts specified.
+     * <p>
+     * Once the subscription is terminated,
+     * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
+     * framework to finish listening for NOTIFY responses.
+     *
+     * @param uris A {@link Collection} of the {@link Uri}s that the framework is requesting the
+     * UCE capabilities for.
+     * @param cb The callback of the subscribe request.
+     */
+    // executor used is defined in the constructor.
+    @SuppressLint("ExecutorRegistration")
+    public void subscribeForCapabilities(@NonNull Collection<Uri> uris,
+            @NonNull SubscribeResponseCallback cb) {
+        // Stub - to be implemented by service
+        Log.w(LOG_TAG, "subscribeForCapabilities called with no implementation.");
+        try {
+            cb.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
+        } catch (ImsException e) {
+            // Do not do anything, this is a stub implementation.
+        }
+    }
+
+    /**
      * The capabilities of this device have been updated and should be published to the network.
      * <p>
      * If this operation succeeds, network response updates should be sent to the framework using
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 15d19a4..541292a 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -114,6 +114,7 @@
     public static final int EVENT_CARRIER_CONFIG_CHANGED = BASE + 54;
     public static final int EVENT_SIM_STATE_UPDATED = BASE + 55;
     public static final int EVENT_APN_UNTHROTTLED = BASE + 56;
+    public static final int EVENT_AIRPLANE_MODE_CHANGED = BASE + 57;
 
     /***** Constants *****/
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 008ba2f..6b2b930 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -168,7 +168,8 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(repetitions = 5,
+                    supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 386dafc5..b61310a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -102,7 +102,7 @@
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Presubmit
+    @FlakyTest
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
         testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 62ccb1a0..6bf4492 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -771,6 +771,24 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="StretchShaderActivity"
+                  android:label="RenderEffect/Stretch"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.android.test.hwui.TEST"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="EdgeEffectStretchActivity"
+                  android:label="RenderEffect/EdgeEffect stretch"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.android.test.hwui.TEST"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name="TextActivity"
              android:label="Text/Simple Text"
              android:theme="@android:style/Theme.NoTitleBar"
diff --git a/tests/HwAccelerationTest/res/layout/stretch_layout.xml b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
new file mode 100644
index 0000000..df5f297
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scroll_view"
+    android:edgeEffectType="stretch"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <HorizontalScrollView
+            android:id="@+id/horizontal_scroll_view"
+            android:edgeEffectType="stretch"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <LinearLayout
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="200dp"
+                    android:src="@drawable/sunset1"/>
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="200dp"
+                    android:src="@drawable/sunset1"/>
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="200dp"
+                    android:src="@drawable/sunset1"/>
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="200dp"
+                    android:src="@drawable/sunset1"/>
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="200dp"
+                    android:src="@drawable/sunset1"/>
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="200dp"
+                    android:src="@drawable/sunset1"/>
+            </LinearLayout>
+        </HorizontalScrollView>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:src="@drawable/sunset1"/>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:src="@drawable/sunset1"/>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:src="@drawable/sunset1"/>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:src="@drawable/sunset1"/>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:src="@drawable/sunset1"/>
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:src="@drawable/sunset1"/>
+
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
new file mode 100644
index 0000000..f0e6299
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.HorizontalScrollView;
+import android.widget.ScrollView;
+
+public class EdgeEffectStretchActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.stretch_layout);
+        HorizontalScrollView hsv = findViewById(R.id.horizontal_scroll_view);
+        hsv.setStretchDistance(50f);
+
+        ScrollView sv = findViewById(R.id.scroll_view);
+        sv.setStretchDistance(50f);
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
new file mode 100644
index 0000000..9bd933a
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2021 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.test.hwui;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderEffect;
+import android.graphics.RuntimeShader;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class StretchShaderActivity extends Activity {
+
+    private static final float MAX_STRETCH_INTENSITY = 1.5f;
+    private static final float STRETCH_AFFECTED_DISTANCE = 1.0f;
+
+    private float mScrollX = 0f;
+    private float mScrollY = 0f;
+
+    private float mMaxStretchIntensity = MAX_STRETCH_INTENSITY;
+    private float mStretchAffectedDistance = STRETCH_AFFECTED_DISTANCE;
+
+    private float mOverscrollX = 25f;
+    private float mOverscrollY = 25f;
+
+    private RuntimeShader mRuntimeShader;
+    private ImageView mImageView;
+    private ImageView mTestImageView;
+
+    private Bitmap mBitmap;
+
+    private StretchDrawable mStretchDrawable = new StretchDrawable();
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout linearLayout = new LinearLayout(this);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+        mBitmap = ((BitmapDrawable) getDrawable(R.drawable.sunset1)).getBitmap();
+        mRuntimeShader = new RuntimeShader(SKSL, false);
+
+        BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
+                Shader.TileMode.CLAMP);
+        mRuntimeShader.setInputShader("uContentTexture", bitmapShader);
+
+        mImageView = new ImageView(this);
+
+        mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+        mImageView.setImageDrawable(new ColorDrawable(Color.CYAN));
+
+        TextView overscrollXText = new TextView(this);
+        overscrollXText.setText("Overscroll X");
+
+        SeekBar overscrollXBar = new SeekBar(this);
+        overscrollXBar.setProgress(0);
+        overscrollXBar.setMin(-50);
+        overscrollXBar.setMax(50);
+        overscrollXBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mOverscrollX = progress;
+                overscrollXText.setText("Overscroll X: " + mOverscrollX);
+                updateShader();
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        TextView overscrollYText = new TextView(this);
+        overscrollYText.setText("Overscroll Y");
+
+        SeekBar overscrollYBar = new SeekBar(this);
+        overscrollYBar.setProgress(0);
+        overscrollYBar.setMin(-50);
+        overscrollYBar.setMax(50);
+        overscrollYBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mOverscrollY = progress;
+                overscrollYText.setText("Overscroll Y: " + mOverscrollY);
+                updateShader();
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        TextView scrollXText = new TextView(this);
+        scrollXText.setText("Scroll X");
+        SeekBar scrollXSeekBar = new SeekBar(this);
+        scrollXSeekBar.setMin(0);
+        scrollXSeekBar.setMax(100);
+        scrollXSeekBar.setProgress(0);
+        scrollXSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mScrollX = (progress / 100f);
+                scrollXText.setText("Scroll X: " + mScrollY);
+                updateShader();
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        TextView scrollYText = new TextView(this);
+        scrollYText.setText("Scroll Y");
+        SeekBar scrollYSeekBar = new SeekBar(this);
+        scrollYSeekBar.setMin(0);
+        scrollYSeekBar.setMax(100);
+        scrollYSeekBar.setProgress(0);
+        scrollYSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mScrollY = (progress / 100f);
+                scrollYText.setText("Scroll Y: " + mScrollY);
+                updateShader();
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        TextView stretchIntensityText = new TextView(this);
+        int stretchProgress = (int) (mMaxStretchIntensity * 100);
+        stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+        SeekBar stretchIntensitySeekbar = new SeekBar(this);
+        stretchIntensitySeekbar.setProgress(stretchProgress);
+        stretchIntensitySeekbar.setMin(1);
+        stretchIntensitySeekbar.setMax((int) (MAX_STRETCH_INTENSITY * 100));
+        stretchIntensitySeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mMaxStretchIntensity = progress / 100f;
+                stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+                updateShader();
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        TextView stretchDistanceText = new TextView(this);
+        stretchDistanceText.setText("StretchDistance");
+        SeekBar stretchDistanceSeekbar = new SeekBar(this);
+        stretchDistanceSeekbar.setMin(0);
+        stretchDistanceSeekbar.setProgress((int) (mStretchAffectedDistance * 100));
+        stretchDistanceSeekbar.setMax(100);
+        stretchDistanceSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mStretchAffectedDistance = progress / 100f;
+                stretchDistanceText.setText("StretchDistance: " + mStretchAffectedDistance);
+                updateShader();
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+
+        linearLayout.addView(mImageView,
+                new LinearLayout.LayoutParams(
+                        mBitmap.getWidth(),
+                        mBitmap.getHeight())
+        );
+
+        linearLayout.addView(overscrollXText,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                ));
+        linearLayout.addView(overscrollXBar,
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT
+                )
+        );
+
+        linearLayout.addView(overscrollYText,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                ));
+        linearLayout.addView(overscrollYBar,
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT
+                )
+        );
+
+        linearLayout.addView(scrollXText,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                ));
+
+        linearLayout.addView(scrollXSeekBar,
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT
+                ));
+
+        linearLayout.addView(scrollYText,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                ));
+
+        linearLayout.addView(scrollYSeekBar,
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT
+                ));
+
+        linearLayout.addView(stretchIntensityText,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                )
+        );
+
+        linearLayout.addView(stretchIntensitySeekbar,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.MATCH_PARENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                )
+        );
+
+        linearLayout.addView(stretchDistanceText,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                ));
+
+        linearLayout.addView(stretchDistanceSeekbar,
+                new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.MATCH_PARENT,
+                        LinearLayout.LayoutParams.WRAP_CONTENT
+                ));
+
+        ImageView test = new ImageView(this);
+        mStretchDrawable.setBitmap(mBitmap);
+        test.setImageDrawable(mStretchDrawable);
+
+        mTestImageView = test;
+        linearLayout.addView(test,
+                new LinearLayout.LayoutParams(mBitmap.getWidth(), mBitmap.getHeight()));
+
+        setContentView(linearLayout);
+
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mImageView.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        updateShader();
+                        mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
+                        return false;
+                    }
+                });
+    }
+
+    private void updateShader() {
+        final float width = mImageView.getWidth();
+        final float height = mImageView.getHeight();
+        final float distanceNotStretched = mStretchAffectedDistance;
+        final float normOverScrollDistX = mOverscrollX / width;
+        final float normOverScrollDistY = mOverscrollY / height;
+        final float distanceStretchedX =
+                mStretchAffectedDistance
+                        / (1 + Math.abs(normOverScrollDistX) * mMaxStretchIntensity);
+        final float distanceStretchedY =
+                mStretchAffectedDistance
+                        / (1 + Math.abs(normOverScrollDistY) * mMaxStretchIntensity);
+        final float diffX = distanceStretchedX - distanceNotStretched;
+        final float diffY = distanceStretchedY - distanceNotStretched;
+        float uScrollX = mScrollX;
+        float uScrollY = mScrollY;
+
+        mRuntimeShader.setUniform("uMaxStretchIntensity", mMaxStretchIntensity);
+        mRuntimeShader.setUniform("uStretchAffectedDist", mStretchAffectedDistance);
+        mRuntimeShader.setUniform("uDistanceStretchedX", distanceStretchedX);
+        mRuntimeShader.setUniform("uDistanceStretchedY", distanceStretchedY);
+        mRuntimeShader.setUniform("uDistDiffX", diffX);
+        mRuntimeShader.setUniform("uDistDiffY", diffY);
+        mRuntimeShader.setUniform("uOverscrollX", normOverScrollDistX);
+        mRuntimeShader.setUniform("uOverscrollY", normOverScrollDistY);
+        mRuntimeShader.setUniform("uScrollX", uScrollX);
+        mRuntimeShader.setUniform("uScrollY", uScrollY);
+        mRuntimeShader.setUniform("viewportWidth", width);
+        mRuntimeShader.setUniform("viewportHeight", height);
+
+        mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+
+        mStretchDrawable.setStretchDistance(mStretchAffectedDistance);
+        mStretchDrawable.setOverscrollX(normOverScrollDistX);
+        mStretchDrawable.setOverscrollY(normOverScrollDistY);
+    }
+
+    private static class StretchDrawable extends Drawable {
+
+        private float mStretchDistance = 0;
+        private float mOverScrollX = 0f;
+        private float mOverScrollY = 0f;
+        private Bitmap mBitmap = null;
+
+        public void setStretchDistance(float stretchDistance) {
+            mStretchDistance = stretchDistance;
+            invalidateSelf();
+        }
+
+        public void setOverscrollX(float overscrollX) {
+            mOverScrollX = overscrollX;
+            invalidateSelf();
+        }
+
+        public void setOverscrollY(float overscrollY) {
+            mOverScrollY = overscrollY;
+            invalidateSelf();
+        }
+
+        public void setBitmap(Bitmap bitmap) {
+            mBitmap = bitmap;
+            invalidateSelf();
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            if (mStretchDistance > 0 && canvas instanceof RecordingCanvas) {
+                Rect bounds = getBounds();
+                ((RecordingCanvas) canvas).mNode.stretch(
+                        0,
+                        0,
+                        bounds.width(),
+                        bounds.height(),
+                        mOverScrollX,
+                        mOverScrollY,
+                        mStretchDistance
+                );
+            }
+            if (mBitmap != null) {
+                canvas.drawBitmap(mBitmap, 0f, 0f, null);
+            }
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+
+        }
+
+        @Override
+        public int getOpacity() {
+            return 0;
+        }
+    }
+
+    private static final String SKSL = "in shader uContentTexture;\n"
+            + "uniform float uMaxStretchIntensity; // multiplier to apply to scale effect\n"
+            + "uniform float uStretchAffectedDist; // Maximum percentage to stretch beyond bounds"
+            + " of target\n"
+            + "\n"
+            + "// Distance stretched as a function of the normalized overscroll times scale "
+            + "intensity\n"
+            + "uniform float uDistanceStretchedX;\n"
+            + "uniform float uDistanceStretchedY;\n"
+            + "uniform float uDistDiffX;\n"
+            + "uniform float uDistDiffY; // Difference between the peak stretch amount and "
+            + "overscroll amount normalized\n"
+            + "uniform float uScrollX; // Horizontal offset represented as a ratio of pixels "
+            + "divided by the target width\n"
+            + "uniform float uScrollY; // Vertical offset represented as a ratio of pixels "
+            + "divided by the target height\n"
+            + "uniform float uOverscrollX; // Normalized overscroll amount in the horizontal "
+            + "direction\n"
+            + "uniform float uOverscrollY; // Normalized overscroll amount in the vertical "
+            + "direction\n"
+            + "\n"
+            + "uniform float viewportWidth; // target height in pixels\n"
+            + "uniform float viewportHeight; // target width in pixels\n"
+            + "\n"
+            + "vec4 main(vec2 coord) {\n"
+            + "\n"
+            + "    // Normalize SKSL pixel coordinate into a unit vector\n"
+            + "    vec2 uv = vec2(coord.x / viewportWidth, coord.y / viewportHeight);\n"
+            + "    float inU = uv.x;\n"
+            + "    float inV = uv.y;\n"
+            + "    float outU;\n"
+            + "    float outV;\n"
+            + "    float stretchIntensity;\n"
+            + "\n"
+            + "    // Add the normalized scroll position within scrolling list\n"
+            + "    inU += uScrollX;\n"
+            + "    inV += uScrollY;\n"
+            + "\n"
+            + "    outU = inU;\n"
+            + "    outV = inV;\n"
+            + "    if (uOverscrollX > 0) {\n"
+            + "        if (inU <= uStretchAffectedDist) {\n"
+            + "            inU = uStretchAffectedDist - inU;\n"
+            + "            float posBasedVariation = smoothstep(0., uStretchAffectedDist, inU);\n"
+            + "            stretchIntensity = uMaxStretchIntensity * uOverscrollX * "
+            + "posBasedVariation;\n"
+            + "            outU = uDistanceStretchedX - (inU / (1. + stretchIntensity));\n"
+            + "        } else {\n"
+            + "            outU = uDistDiffX + inU;\n"
+            + "        }\n"
+            + "    }\n"
+            + "\n"
+            + "     if (uOverscrollX < 0) {\n"
+            + "            float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+            + "            if (inU >= stretchAffectedDist) {\n"
+            + "                inU = inU - stretchAffectedDist;\n"
+            + "                float posBasedVariation = (smoothstep(0., uStretchAffectedDist, "
+            + "inU));\n"
+            + "                stretchIntensity = uMaxStretchIntensity * (-uOverscrollX) * "
+            + "posBasedVariation;\n"
+            + "                outU = 1 - (uDistanceStretchedX - (inU / (1. + stretchIntensity)))"
+            + ";\n"
+            + "            } else if (inU < stretchAffectedDist) {\n"
+            + "                outU = -uDistDiffX + inU;\n"
+            + "            }\n"
+            + "        }\n"
+            + "\n"
+            + "    if (uOverscrollY > 0) {\n"
+            + "        if (inV <= uStretchAffectedDist) {\n"
+            + "            inV = uStretchAffectedDist - inV;\n"
+            + "            float posBasedVariation = smoothstep(0., uStretchAffectedDist, inV);\n"
+            + "            stretchIntensity = uMaxStretchIntensity * uOverscrollY * "
+            + "posBasedVariation;\n"
+            + "            outV = uDistanceStretchedY - (inV / (1. + stretchIntensity));\n"
+            + "        } else if (inV >= uStretchAffectedDist) {\n"
+            + "            outV = uDistDiffY + inV;\n"
+            + "        }\n"
+            + "    }\n"
+            + "\n"
+            + "    if (uOverscrollY < 0) {\n"
+            + "        float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+            + "        if (inV >= stretchAffectedDist) {\n"
+            + "            inV = inV - stretchAffectedDist;\n"
+            + "            float posBasedVariation = (smoothstep(0., uStretchAffectedDist, inV));\n"
+            + "            stretchIntensity = uMaxStretchIntensity * (-uOverscrollY) * "
+            + "posBasedVariation;\n"
+            + "            outV = 1 - (uDistanceStretchedY - (inV / (1. + stretchIntensity)));\n"
+            + "        } else if (inV < stretchAffectedDist) {\n"
+            + "            outV = -uDistDiffY + inV;\n"
+            + "        }\n"
+            + "    }\n"
+            + "\n"
+            + "    uv.x = outU;\n"
+            + "    uv.y = outV;\n"
+            + "    coord.x = uv.x * viewportWidth;\n"
+            + "    coord.y = uv.y * viewportHeight;\n"
+            + "    return sample(uContentTexture, coord);\n"
+            + "}";
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
new file mode 100644
index 0000000..2e985fb
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 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.test.input
+
+import android.view.InputDevice.SOURCE_MOUSE
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEventAssigner
+import android.view.KeyEvent
+import android.view.MotionEvent
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, eventTime: Long, source: Int): MotionEvent {
+    val downTime: Long = 10
+    val x = 1f
+    val y = 2f
+    val pressure = 3f
+    val size = 1f
+    val metaState = 0
+    val xPrecision = 0f
+    val yPrecision = 0f
+    val deviceId = 1
+    val edgeFlags = 0
+    val displayId = 0
+    return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+            xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+fun createKeyEvent(action: Int, eventTime: Long): KeyEvent {
+    val code = KeyEvent.KEYCODE_A
+    val repeat = 0
+    return KeyEvent(eventTime, eventTime, action, code, repeat)
+}
+
+class InputEventAssignerTest {
+    companion object {
+        private const val TAG = "InputEventAssignerTest"
+    }
+
+    /**
+     * A single MOVE event should be assigned to the next available frame.
+     */
+    @Test
+    fun testTouchGesture() {
+        val assigner = InputEventAssigner()
+        val event = createMotionEvent(MotionEvent.ACTION_MOVE, 10, SOURCE_TOUCHSCREEN)
+        val eventId = assigner.processEvent(event)
+        assertEquals(event.id, eventId)
+    }
+
+    /**
+     * DOWN event should be used until a vsync comes in. After vsync, the latest event should be
+     * produced.
+     */
+    @Test
+    fun testTouchDownWithMove() {
+        val assigner = InputEventAssigner()
+        val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_TOUCHSCREEN)
+        val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_TOUCHSCREEN)
+        val move2 = createMotionEvent(MotionEvent.ACTION_MOVE, 13, SOURCE_TOUCHSCREEN)
+        val move3 = createMotionEvent(MotionEvent.ACTION_MOVE, 14, SOURCE_TOUCHSCREEN)
+        val move4 = createMotionEvent(MotionEvent.ACTION_MOVE, 15, SOURCE_TOUCHSCREEN)
+        var eventId = assigner.processEvent(down)
+        assertEquals(down.id, eventId)
+        eventId = assigner.processEvent(move1)
+        assertEquals(down.id, eventId)
+        eventId = assigner.processEvent(move2)
+        // Even though we already had 2 move events, there was no choreographer callback yet.
+        // Therefore, we should still get the id of the down event
+        assertEquals(down.id, eventId)
+
+        // Now send CALLBACK_INPUT to the assigner. It should provide the latest motion event
+        assigner.onChoreographerCallback()
+        eventId = assigner.processEvent(move3)
+        assertEquals(move3.id, eventId)
+        eventId = assigner.processEvent(move4)
+        assertEquals(move4.id, eventId)
+    }
+
+    /**
+     * Similar to the above test, but with SOURCE_MOUSE. Since we don't have down latency
+     * concept for non-touchscreens, the latest input event will be used.
+     */
+    @Test
+    fun testMouseDownWithMove() {
+        val assigner = InputEventAssigner()
+        val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_MOUSE)
+        val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_MOUSE)
+        var eventId = assigner.processEvent(down)
+        assertEquals(down.id, eventId)
+        eventId = assigner.processEvent(move1)
+        assertEquals(move1.id, eventId)
+    }
+
+    /**
+     * KeyEvents are processed immediately, so the latest event should be returned.
+     */
+    @Test
+    fun testKeyEvent() {
+        val assigner = InputEventAssigner()
+        val down = createKeyEvent(KeyEvent.ACTION_DOWN, 20)
+        var eventId = assigner.processEvent(down)
+        assertEquals(down.id, eventId)
+        val up = createKeyEvent(KeyEvent.ACTION_UP, 21)
+        eventId = assigner.processEvent(up)
+        // DOWN is only sticky for Motions, not for keys
+        assertEquals(up.id, eventId)
+        assigner.onChoreographerCallback()
+        val down2 = createKeyEvent(KeyEvent.ACTION_DOWN, 22)
+        eventId = assigner.processEvent(down2)
+        assertEquals(down2.id, eventId)
+    }
+}
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
index c19e5cc..c01d32b 100644
--- a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -17,6 +17,7 @@
 package com.android.test.input
 
 import android.graphics.FrameInfo
+import android.os.IInputConstants.INVALID_INPUT_EVENT_ID
 import android.os.SystemClock
 import android.view.ViewFrameInfo
 import com.google.common.truth.Truth.assertThat
@@ -33,8 +34,7 @@
     @Before
     fun setUp() {
         mViewFrameInfo.reset()
-        mViewFrameInfo.updateOldestInputEvent(10)
-        mViewFrameInfo.updateNewestInputEvent(20)
+        mViewFrameInfo.setInputEvent(139)
         mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED
         mTimeStarted = SystemClock.uptimeNanos()
         mViewFrameInfo.markDrawStart()
@@ -43,8 +43,6 @@
     @Test
     fun testPopulateFields() {
         assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted)
-        assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(10)
-        assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(20)
         assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
     }
 
@@ -53,8 +51,6 @@
         mViewFrameInfo.reset()
         // Ensure that the original object is reset correctly
         assertThat(mViewFrameInfo.drawStart).isEqualTo(0)
-        assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(0)
-        assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(0)
         assertThat(mViewFrameInfo.flags).isEqualTo(0)
     }
 
@@ -62,12 +58,13 @@
     fun testUpdateFrameInfoFromViewFrameInfo() {
         val frameInfo = FrameInfo()
         // By default, all values should be zero
-        // TODO(b/169866723): Use InputEventAssigner and assert INPUT_EVENT_ID
+        assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(INVALID_INPUT_EVENT_ID)
         assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
         assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
 
         // The values inside FrameInfo should match those from ViewFrameInfo after we update them
         mViewFrameInfo.populateFrameInfo(frameInfo)
+        assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(139)
         assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
                 FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
         assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index ee24d48..d4f1ad3 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -26,13 +26,9 @@
     srcs: ["src/**/*.java"],
     libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
     static_libs: [
-        "block_device_writer_jar",
         "frameworks-base-hostutils",
     ],
     test_suites: ["general-tests", "vts"],
-    target_required: [
-        "block_device_writer_module",
-    ],
     data: [
         ":NotoColorEmojiTtf",
         ":UpdatableSystemFontTestCertDer",
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
index 7b919bd..efe5d70 100644
--- a/tests/UpdatableSystemFontTest/AndroidTest.xml
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -21,7 +21,6 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
         <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
         <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
         <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index e249f8a9..92fa498 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -21,7 +21,6 @@
 
 import android.platform.test.annotations.RootPermissionTest;
 
-import com.android.blockdevicewriter.BlockDeviceWriter;
 import com.android.fsverity.AddFsVerityCertRule;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -144,30 +143,6 @@
         assertThat(fontPathAfterReboot).isEqualTo(fontPath);
     }
 
-    @Test
-    public void reboot_clearDamagedFiles() throws Exception {
-        expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
-                TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG));
-        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
-        assertThat(fontPath).startsWith("/data/fonts/files/");
-        assertThat(BlockDeviceWriter.canReadByte(getDevice(), fontPath, 0)).isTrue();
-
-        BlockDeviceWriter.damageFileAgainstBlockDevice(getDevice(), fontPath, 0);
-        expectRemoteCommandToSucceed("stop");
-        // We have to make sure system_server is gone before dropping caches, because system_server
-        // process holds font memory maps and prevents cache eviction.
-        waitUntilSystemServerIsGone();
-        BlockDeviceWriter.assertFileNotOpen(getDevice(), fontPath);
-        BlockDeviceWriter.dropCaches(getDevice());
-        assertThat(BlockDeviceWriter.canReadByte(getDevice(), fontPath, 0)).isFalse();
-
-        expectRemoteCommandToSucceed("start");
-        waitUntilFontCommandIsReady();
-        String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_TTF);
-        assertWithMessage("Damaged file should be deleted")
-                .that(fontPathAfterReboot).startsWith("/system");
-    }
-
     private String getFontPath(String fontFileName) throws Exception {
         // TODO: add a dedicated command for testing.
         String lines = expectRemoteCommandToSucceed("cmd font dump");
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
index 7a60cc1..4cdf6a2 100644
--- a/tests/net/common/java/android/net/CaptivePortalTest.java
+++ b/tests/net/common/java/android/net/CaptivePortalTest.java
@@ -24,7 +24,6 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 
@@ -54,12 +53,6 @@
         public void appRequest(final int request) throws RemoteException {
             mCode = request;
         }
-
-        @Override
-        public void logEvent(int eventId, String packageName) throws RemoteException {
-            mCode = eventId;
-            mPackageName = packageName;
-        }
     }
 
     private interface TestFunctor {
@@ -98,12 +91,14 @@
         assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED);
     }
 
+    /**
+     * Test testLogEvent is expected to do nothing but shouldn't crash, because the API logEvent
+     * has been deprecated.
+     */
     @Test
     public void testLogEvent() {
         final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
-                MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
+                0,
                 TEST_PACKAGE_NAME));
-        assertEquals(result.mCode, MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
-        assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
     }
 }
diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
index 56b56ef..0ca4d95 100644
--- a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
+++ b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
@@ -63,10 +63,10 @@
 
     @Test
     fun testParcelUnparcel() {
-        val emptySnapshot = NetworkStateSnapshot(LinkProperties(), NetworkCapabilities(),
-                Network(TEST_NETID), null, TYPE_NONE)
+        val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(),
+                LinkProperties(), null, TYPE_NONE)
         val snapshot = NetworkStateSnapshot(
-                TEST_LINK_PROPERTIES, TEST_CAPABILITIES, Network(TEST_NETID), TEST_IMSI, TYPE_WIFI)
+                Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI)
         assertParcelSane(emptySnapshot, 5)
         assertParcelSane(snapshot, 5)
     }
diff --git a/tests/net/common/java/android/net/UidRangeTest.java b/tests/net/common/java/android/net/UidRangeTest.java
new file mode 100644
index 0000000..1b1c954
--- /dev/null
+++ b/tests/net/common/java/android/net/UidRangeTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
+import static android.os.UserHandle.SYSTEM;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.os.UserHandle.getUid;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.os.Build;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UidRangeTest {
+
+    /*
+     * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
+     * UidRangeParcel objects.
+     */
+
+    @Rule
+    public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
+    @Test
+    public void testSingleItemUidRangeAllowed() {
+        new UidRange(123, 123);
+        new UidRange(0, 0);
+        new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void testNegativeUidsDisallowed() {
+        try {
+            new UidRange(-2, 100);
+            fail("Exception not thrown for negative start UID");
+        } catch (IllegalArgumentException expected) {
+        }
+
+        try {
+            new UidRange(-200, -100);
+            fail("Exception not thrown for negative stop UID");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testStopLessThanStartDisallowed() {
+        final int x = 4195000;
+        try {
+            new UidRange(x, x - 1);
+            fail("Exception not thrown for negative-length UID range");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testGetStartAndEndUser() throws Exception {
+        final UidRange uidRangeOfPrimaryUser = new UidRange(
+                getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100));
+        final UidRange uidRangeOfSecondaryUser = new UidRange(
+                getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
+
+        final UidRange uidRangeForDifferentUsers = new UidRange(
+                getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testCreateForUser() throws Exception {
+        final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM);
+        final UidRange uidRangeOfSecondaryUser = UidRange.createForUser(
+                UserHandle.of(USER_SYSTEM + 1));
+        assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start);
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
+        assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
+        assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
+    }
+}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 9ed55f0..2a2dc56 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.net.integrationtests
 
+import android.app.usage.NetworkStatsManager
 import android.content.ComponentName
 import android.content.Context
 import android.content.Context.BIND_AUTO_CREATE
@@ -25,7 +26,6 @@
 import android.net.ConnectivityManager
 import android.net.IDnsResolver
 import android.net.INetd
-import android.net.INetworkStatsService
 import android.net.LinkProperties
 import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
@@ -37,7 +37,6 @@
 import android.net.metrics.IpConnectivityLog
 import android.os.ConditionVariable
 import android.os.IBinder
-import android.os.INetworkManagementService
 import android.os.SystemConfigManager
 import android.os.UserHandle
 import android.testing.TestableContext
@@ -87,9 +86,7 @@
     // lateinit used here for mocks as they need to be reinitialized between each test and the test
     // should crash if they are used before being initialized.
     @Mock
-    private lateinit var netManager: INetworkManagementService
-    @Mock
-    private lateinit var statsService: INetworkStatsService
+    private lateinit var statsManager: NetworkStatsManager
     @Mock
     private lateinit var log: IpConnectivityLog
     @Mock
@@ -172,12 +169,13 @@
         service = TestConnectivityService(makeDependencies())
         cm = ConnectivityManager(context, service)
         context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
+        context.addMockSystemService(Context.NETWORK_STATS_SERVICE, statsManager)
 
         service.systemReadyInternal()
     }
 
     private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
-            context, netManager, statsService, dnsResolver, log, netd, deps)
+            context, dnsResolver, log, netd, deps)
 
     private fun makeDependencies(): ConnectivityService.Dependencies {
         val deps = spy(ConnectivityService.Dependencies())
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
index 2e1c29a..3a8d600 100644
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -129,6 +129,7 @@
             checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
         }
         checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
+        checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96);
         checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
     }
 
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 27224c2..64b774c 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -20,14 +20,13 @@
 import android.net.ConnectivityManager.TYPE_MOBILE
 import android.net.ConnectivityManager.TYPE_WIFI
 import android.net.NetworkIdentity.SUBTYPE_COMBINED
-import android.net.NetworkIdentity.OEM_NONE;
-import android.net.NetworkIdentity.OEM_PAID;
-import android.net.NetworkIdentity.OEM_PRIVATE;
+import android.net.NetworkIdentity.OEM_NONE
+import android.net.NetworkIdentity.OEM_PAID
+import android.net.NetworkIdentity.OEM_PRIVATE
 import android.net.NetworkIdentity.buildNetworkIdentity
 import android.net.NetworkStats.DEFAULT_NETWORK_ALL
 import android.net.NetworkStats.METERED_ALL
 import android.net.NetworkStats.ROAMING_ALL
-import android.net.NetworkTemplate.MATCH_ETHERNET
 import android.net.NetworkTemplate.MATCH_MOBILE
 import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
 import android.net.NetworkTemplate.MATCH_WIFI
@@ -50,7 +49,6 @@
 import kotlin.test.assertFalse
 import kotlin.test.assertNotEquals
 import kotlin.test.assertTrue
-import kotlin.test.fail
 
 private const val TEST_IMSI1 = "imsi1"
 private const val TEST_IMSI2 = "imsi2"
@@ -60,17 +58,17 @@
 class NetworkTemplateTest {
     private val mockContext = mock(Context::class.java)
 
-    private fun buildMobileNetworkState(subscriberId: String): NetworkState =
+    private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
             buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
-    private fun buildWifiNetworkState(ssid: String): NetworkState =
+    private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot =
             buildNetworkState(TYPE_WIFI, ssid = ssid)
 
     private fun buildNetworkState(
         type: Int,
         subscriberId: String? = null,
         ssid: String? = null,
-        oemManaged: Int = OEM_NONE,
-    ): NetworkState {
+        oemManaged: Int = OEM_NONE
+    ): NetworkStateSnapshot {
         val lp = LinkProperties()
         val caps = NetworkCapabilities().apply {
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
@@ -81,7 +79,7 @@
             setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
                     (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
         }
-        return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId)
+        return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
     }
 
     private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
@@ -179,7 +177,7 @@
                 OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
 
         // Verify that "not OEM managed network" constants are equal.
-        assertEquals(OEM_MANAGED_NO, OEM_NONE);
+        assertEquals(OEM_MANAGED_NO, OEM_NONE)
 
         // Verify the constants don't conflict.
         assertEquals(constantValues.size, constantValues.distinct().count())
@@ -201,8 +199,13 @@
      * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
      *         one of {@code TEST_SSID*}.
      */
-    private fun matchOemManagedIdent(networkType: Int, matchType:Int, subscriberId: String? = null,
-            templateSsid: String? = null, identSsid: String? = null) {
+    private fun matchOemManagedIdent(
+        networkType: Int,
+        matchType: Int,
+        subscriberId: String? = null,
+        templateSsid: String? = null,
+        identSsid: String? = null
+    ) {
         val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
         // A null subscriberId needs a null matchSubscriberIds argument as well.
         val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId)
diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java
deleted file mode 100644
index ea1df09..0000000
--- a/tests/net/java/android/net/UidRangeTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class UidRangeTest {
-
-  /*
-   * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
-   * UidRangeParcel objects.
-   */
-
-    @Test
-    public void testSingleItemUidRangeAllowed() {
-        new UidRange(123, 123);
-        new UidRange(0, 0);
-        new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
-    }
-
-    @Test
-    public void testNegativeUidsDisallowed() {
-        try {
-            new UidRange(-2, 100);
-            fail("Exception not thrown for negative start UID");
-        } catch (IllegalArgumentException expected) {
-        }
-
-        try {
-            new UidRange(-200, -100);
-            fail("Exception not thrown for negative stop UID");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testStopLessThanStartDisallowed() {
-        final int x = 4195000;
-        try {
-            new UidRange(x, x - 1);
-            fail("Exception not thrown for negative-length UID range");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1cfc3f9..ba64b30 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -91,6 +91,10 @@
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 
@@ -145,6 +149,7 @@
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -176,7 +181,6 @@
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
-import android.net.INetworkStatsService;
 import android.net.IOnSetOemNetworkPreferenceListener;
 import android.net.IQosCallback;
 import android.net.InetAddresses;
@@ -199,7 +203,6 @@
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
-import android.net.NetworkState;
 import android.net.NetworkTestResultParcelable;
 import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
@@ -218,6 +221,8 @@
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
 import android.net.metrics.IpConnectivityLog;
+import android.net.resolv.aidl.Nat64PrefixEventParcel;
+import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
@@ -244,7 +249,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.KeyStore;
 import android.system.Os;
 import android.telephony.TelephonyManager;
 import android.telephony.data.EpsBearerQosSessionAttributes;
@@ -276,6 +280,7 @@
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
 import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.testutils.ExceptionUtils;
@@ -345,6 +350,9 @@
     private static final String TAG = "ConnectivityServiceTest";
 
     private static final int TIMEOUT_MS = 500;
+    // Broadcasts can take a long time to be delivered. The test will not wait for that long unless
+    // there is a failure, so use a long timeout.
+    private static final int BROADCAST_TIMEOUT_MS = 30_000;
     private static final int TEST_LINGER_DELAY_MS = 400;
     private static final int TEST_NASCENT_DELAY_MS = 300;
     // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish
@@ -407,6 +415,8 @@
     private QosCallbackMockHelper mQosCallbackMockHelper;
     private QosCallbackTracker mQosCallbackTracker;
     private VpnManagerService mVpnManagerService;
+    private TestNetworkCallback mDefaultNetworkCallback;
+    private TestNetworkCallback mSystemDefaultNetworkCallback;
 
     // State variables required to emulate NetworkPolicyManagerService behaviour.
     private int mUidRules = RULE_NONE;
@@ -414,7 +424,7 @@
 
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
-    @Mock INetworkStatsService mStatsService;
+    @Mock NetworkStatsManager mStatsManager;
     @Mock IBatteryStats mBatteryStatsService;
     @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
@@ -431,7 +441,7 @@
     @Mock MockableSystemProperties mSystemProperties;
     @Mock EthernetManager mEthernetManager;
     @Mock NetworkPolicyManager mNetworkPolicyManager;
-    @Mock KeyStore mKeyStore;
+    @Mock VpnProfileStore mVpnProfileStore;
     @Mock SystemConfigManager mSystemConfigManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
@@ -530,6 +540,7 @@
             if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
             if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
             if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
+            if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
             return super.getSystemService(name);
         }
 
@@ -1115,7 +1126,7 @@
                             return mDeviceIdleInternal;
                         }
                     },
-                    mNetworkManagementService, mMockNetd, userId, mKeyStore);
+                    mNetworkManagementService, mMockNetd, userId, mVpnProfileStore);
         }
 
         public void setUids(Set<UidRange> uids) {
@@ -1294,8 +1305,9 @@
                 return mVMSHandlerThread;
             }
 
-            public KeyStore getKeyStore() {
-                return mKeyStore;
+            @Override
+            public VpnProfileStore getVpnProfileStore() {
+                return mVpnProfileStore;
             }
 
             public INetd getNetd() {
@@ -1462,8 +1474,6 @@
         mDeps = makeDependencies();
         returnRealCallingUid();
         mService = new ConnectivityService(mServiceContext,
-                mNetworkManagementService,
-                mStatsService,
                 mMockDnsResolver,
                 mock(IpConnectivityLog.class),
                 mMockNetd,
@@ -1547,6 +1557,7 @@
 
     @After
     public void tearDown() throws Exception {
+        unregisterDefaultNetworkCallbacks();
         setAlwaysOnNetworks(false);
         if (mCellNetworkAgent != null) {
             mCellNetworkAgent.disconnect();
@@ -1680,7 +1691,7 @@
         }
 
         public Intent expectBroadcast() throws Exception {
-            return expectBroadcast(TIMEOUT_MS);
+            return expectBroadcast(BROADCAST_TIMEOUT_MS);
         }
 
         public void expectNoBroadcast(int timeoutMs) throws Exception {
@@ -5478,18 +5489,19 @@
         assertEquals(expectedSet, actualSet);
     }
 
-    private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
+    private void expectNetworkStatus(Network[] networks, String defaultIface,
             Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
-        ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
-        ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
-                UnderlyingNetworkInfo[].class);
+        ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
+                ArgumentCaptor.forClass(List.class);
 
-        verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
-                any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
+        verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
+                any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
 
-        assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
+        assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks);
 
-        UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
+        UnderlyingNetworkInfo[] infos =
+                vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]);
         if (vpnUid != null) {
             assertEquals("Should have exactly one VPN:", 1, infos.length);
             UnderlyingNetworkInfo info = infos[0];
@@ -5503,8 +5515,9 @@
         }
     }
 
-    private void expectForceUpdateIfaces(Network[] networks, String defaultIface) throws Exception {
-        expectForceUpdateIfaces(networks, defaultIface, null, null, new String[0]);
+    private void expectNetworkStatus(
+            Network[] networks, String defaultIface) throws Exception {
+        expectNetworkStatus(networks, defaultIface, null, null, new String[0]);
     }
 
     @Test
@@ -5524,47 +5537,46 @@
         mCellNetworkAgent.connect(false);
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
-        reset(mStatsService);
+        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        reset(mStatsManager);
 
         // Default network switch should update ifaces.
         mWiFiNetworkAgent.connect(false);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
-        expectForceUpdateIfaces(onlyWifi, WIFI_IFNAME);
-        reset(mStatsService);
+        expectNetworkStatus(onlyWifi, WIFI_IFNAME);
+        reset(mStatsManager);
 
         // Disconnect should update ifaces.
         mWiFiNetworkAgent.disconnect();
         waitForIdle();
-        expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
-        reset(mStatsService);
+        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        reset(mStatsManager);
 
         // Metered change should update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         waitForIdle();
-        expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
-        reset(mStatsService);
+        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        reset(mStatsManager);
 
         mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         waitForIdle();
-        expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
-        reset(mStatsService);
+        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        reset(mStatsManager);
 
         // Temp metered change shouldn't update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
-        verify(mStatsService, never())
-                .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
-                        eq(new UnderlyingNetworkInfo[0]));
-        reset(mStatsService);
+        verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)),
+                any(List.class), eq(MOBILE_IFNAME), any(List.class));
+        reset(mStatsManager);
 
         // Roaming change should update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
         waitForIdle();
-        expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
-        reset(mStatsService);
+        expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+        reset(mStatsManager);
 
         // Test VPNs.
         final LinkProperties lp = new LinkProperties();
@@ -5577,7 +5589,7 @@
                 mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
 
         // A VPN with default (null) underlying networks sets the underlying network's interfaces...
-        expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME});
 
         // ...and updates them as the default network switches.
@@ -5594,9 +5606,9 @@
 
         waitForIdle();
         assertEquals(wifiLp, mService.getActiveLinkProperties());
-        expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{WIFI_IFNAME});
-        reset(mStatsService);
+        reset(mStatsManager);
 
         // A VPN that sets its underlying networks passes the underlying interfaces, and influences
         // the default interface sent to NetworkStatsService by virtue of applying to the system
@@ -5606,22 +5618,22 @@
         // applies to the system server UID should not have any bearing on network stats.
         mMockVpn.setUnderlyingNetworks(onlyCell);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME});
-        reset(mStatsService);
+        reset(mStatsManager);
 
         mMockVpn.setUnderlyingNetworks(cellAndWifi);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME, WIFI_IFNAME});
-        reset(mStatsService);
+        reset(mStatsManager);
 
         // Null underlying networks are ignored.
         mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME, WIFI_IFNAME});
-        reset(mStatsService);
+        reset(mStatsManager);
 
         // If an underlying network disconnects, that interface should no longer be underlying.
         // This doesn't actually work because disconnectAndDestroyNetwork only notifies
@@ -5633,17 +5645,17 @@
         mCellNetworkAgent.disconnect();
         waitForIdle();
         assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
-        expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{MOBILE_IFNAME, WIFI_IFNAME});
 
         // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
         // network for the VPN...
-        verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
-                any(NetworkState[].class), any() /* anyString() doesn't match null */,
-                argThat(infos -> infos[0].underlyingIfaces.size() == 1
-                        && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
-        verifyNoMoreInteractions(mStatsService);
-        reset(mStatsService);
+        verify(mStatsManager, never()).notifyNetworkStatus(any(List.class),
+                any(List.class), any() /* anyString() doesn't match null */,
+                argThat(infos -> infos.get(0).underlyingIfaces.size() == 1
+                        && WIFI_IFNAME.equals(infos.get(0).underlyingIfaces.get(0))));
+        verifyNoMoreInteractions(mStatsManager);
+        reset(mStatsManager);
 
         // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be
         // called again, it does. For example, connect Ethernet, but with a low score, such that it
@@ -5652,13 +5664,13 @@
         mEthernetNetworkAgent.adjustScore(-40);
         mEthernetNetworkAgent.connect(false);
         waitForIdle();
-        verify(mStatsService).forceUpdateIfaces(any(Network[].class),
-                any(NetworkState[].class), any() /* anyString() doesn't match null */,
-                argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
-                        && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
+        verify(mStatsManager).notifyNetworkStatus(any(List.class),
+                any(List.class), any() /* anyString() doesn't match null */,
+                argThat(vpnInfos -> vpnInfos.get(0).underlyingIfaces.size() == 1
+                        && WIFI_IFNAME.equals(vpnInfos.get(0).underlyingIfaces.get(0))));
         mEthernetNetworkAgent.disconnect();
         waitForIdle();
-        reset(mStatsService);
+        reset(mStatsManager);
 
         // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
         // does not return the VPN, so CS does not pass it to NetworkStatsService. This causes
@@ -5668,27 +5680,27 @@
         // Also, for the same reason as above, the active interface passed in is null.
         mMockVpn.setUnderlyingNetworks(new Network[0]);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, null);
-        reset(mStatsService);
+        expectNetworkStatus(wifiAndVpn, null);
+        reset(mStatsManager);
 
         // Specifying only a null underlying network is the same as no networks.
         mMockVpn.setUnderlyingNetworks(onlyNull);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, null);
-        reset(mStatsService);
+        expectNetworkStatus(wifiAndVpn, null);
+        reset(mStatsManager);
 
         // Specifying networks that are all disconnected is the same as specifying no networks.
         mMockVpn.setUnderlyingNetworks(onlyCell);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, null);
-        reset(mStatsService);
+        expectNetworkStatus(wifiAndVpn, null);
+        reset(mStatsManager);
 
         // Passing in null again means follow the default network again.
         mMockVpn.setUnderlyingNetworks(null);
         waitForIdle();
-        expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+        expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
                 new String[]{WIFI_IFNAME});
-        reset(mStatsService);
+        reset(mStatsManager);
     }
 
     @Test
@@ -5921,6 +5933,16 @@
         assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
     }
 
+    private PrivateDnsValidationEventParcel makePrivateDnsValidationEvent(
+            final int netId, final String ipAddress, final String hostname, final int validation) {
+        final PrivateDnsValidationEventParcel event = new PrivateDnsValidationEventParcel();
+        event.netId = netId;
+        event.ipAddress = ipAddress;
+        event.hostname = hostname;
+        event.validation = validation;
+        return event;
+    }
+
     @Test
     public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
         // The default on Android is opportunistic mode ("Automatic").
@@ -5951,8 +5973,9 @@
 
         // Send a validation event for a server that is not part of the current
         // resolver config. The validation event should be ignored.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "",
+                        "145.100.185.18", VALIDATION_RESULT_SUCCESS));
         cellNetworkCallback.assertNoCallback();
 
         // Add a dns server to the LinkProperties.
@@ -5969,20 +5992,23 @@
 
         // Send a validation event containing a hostname that is not part of
         // the current resolver config. The validation event should be ignored.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS));
         cellNetworkCallback.assertNoCallback();
 
         // Send a validation event where validation failed.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "", VALIDATION_RESULT_FAILURE));
         cellNetworkCallback.assertNoCallback();
 
         // Send a validation event where validation succeeded for a server in
         // the current resolver config. A LinkProperties callback with updated
         // private dns fields should be sent.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "", VALIDATION_RESULT_SUCCESS));
         cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
                 mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
@@ -7488,8 +7514,7 @@
     private void setupLegacyLockdownVpn() {
         final String profileName = "testVpnProfile";
         final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
-        when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true);
-        when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
+        when(mVpnProfileStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
 
         final VpnProfile profile = new VpnProfile(profileName);
         profile.name = "My VPN";
@@ -7497,7 +7522,7 @@
         profile.dnsServers = "8.8.8.8";
         profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
         final byte[] encodedProfile = profile.encode();
-        when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
+        when(mVpnProfileStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
     }
 
     private void establishLegacyLockdownVpn(Network underlying) throws Exception {
@@ -7826,6 +7851,16 @@
         return stacked;
     }
 
+    private Nat64PrefixEventParcel makeNat64PrefixEvent(final int netId, final int prefixOperation,
+            final String prefixAddress, final int prefixLength) {
+        final Nat64PrefixEventParcel event = new Nat64PrefixEventParcel();
+        event.netId = netId;
+        event.prefixOperation = prefixOperation;
+        event.prefixAddress = prefixAddress;
+        event.prefixLength = prefixLength;
+        return event;
+    }
+
     @Test
     public void testStackedLinkProperties() throws Exception {
         final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
@@ -7856,7 +7891,6 @@
         cellLp.addRoute(defaultRoute);
         cellLp.addRoute(ipv6Subnet);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
-        reset(mNetworkManagementService);
         reset(mMockDnsResolver);
         reset(mMockNetd);
         reset(mBatteryStatsService);
@@ -7896,7 +7930,6 @@
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -7912,8 +7945,8 @@
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
         Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
         assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
         LinkProperties lpBeforeClat = networkCallback.expectCallback(
                 CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
         assertEquals(0, lpBeforeClat.getStackedLinks().size());
@@ -7953,8 +7986,8 @@
                 .thenReturn(getClatInterfaceConfigParcel(myIpv4));
         // Change the NAT64 prefix without first removing it.
         // Expect clatd to be stopped and started with the new prefix.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kOtherNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0);
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
@@ -7996,15 +8029,14 @@
         verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfigParcel(myIpv4));
 
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
-                kOtherNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getNat64Prefix() == null);
 
@@ -8016,8 +8048,8 @@
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         assertRoutesRemoved(cellNetId, ipv4Subnet);  // Directly-connected routes auto-added.
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
 
@@ -8029,8 +8061,8 @@
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
 
         // NAT64 prefix is removed. Expect that clat is stopped.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
         assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
@@ -8118,8 +8150,8 @@
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
 
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
         expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
 
@@ -8152,8 +8184,8 @@
         inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
 
         // Stopping prefix discovery results in a prefix removed notification.
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, false /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_REMOVED, pref64FromDnsStr, 96));
 
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
@@ -8191,8 +8223,8 @@
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
         expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
         inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
@@ -8233,7 +8265,6 @@
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         mCellNetworkAgent.sendLinkProperties(cellLp);
-        reset(mNetworkManagementService);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
@@ -8927,8 +8958,8 @@
                 ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
                 TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
         return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
-                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
-                0, INVALID_UID, mQosCallbackTracker);
+                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
+                INVALID_UID, mQosCallbackTracker);
     }
 
     @Test
@@ -9467,6 +9498,10 @@
         fail("TOO_MANY_REQUESTS never thrown");
     }
 
+    private UidRange createUidRange(int userId) {
+        return UidRange.createForUser(UserHandle.of(userId));
+    }
+
     private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid)
             throws Exception {
         final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -9801,6 +9836,54 @@
             assertEquals(expectedPerAppNetwork, defaultNetwork);
             assertEquals(expectedOemRequestsSize, defaultRequest.mRequests.size());
         }
+        verifyMultipleDefaultCallbacks(expectedDefaultNetwork, expectedPerAppNetwork);
+    }
+
+    /**
+     * Verify default callbacks for 'available' fire as expected. This will only run if
+     * registerDefaultNetworkCallbacks() was executed prior and will only be different if the
+     * setOemNetworkPreference() per-app API was used for the current process.
+     * @param expectedSystemDefault the expected network for the system default.
+     * @param expectedPerAppDefault the expected network for the current process's default.
+     */
+    private void verifyMultipleDefaultCallbacks(
+            @NonNull final Network expectedSystemDefault,
+            @NonNull final Network expectedPerAppDefault) {
+        if (null != mSystemDefaultNetworkCallback && null != expectedSystemDefault
+                && mService.mNoServiceNetwork.network() != expectedSystemDefault) {
+            // getLastAvailableNetwork() is used as this method can be called successively with
+            // the same network to validate therefore expectAvailableThenValidatedCallbacks
+            // can't be used.
+            assertEquals(mSystemDefaultNetworkCallback.getLastAvailableNetwork(),
+                    expectedSystemDefault);
+        }
+        if (null != mDefaultNetworkCallback && null != expectedPerAppDefault
+                && mService.mNoServiceNetwork.network() != expectedPerAppDefault) {
+            assertEquals(mDefaultNetworkCallback.getLastAvailableNetwork(),
+                    expectedPerAppDefault);
+        }
+    }
+
+    private void registerDefaultNetworkCallbacks() {
+        // Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
+        mServiceContext.setPermission(
+                Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+        mSystemDefaultNetworkCallback = new TestNetworkCallback();
+        mDefaultNetworkCallback = new TestNetworkCallback();
+        mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
+                new Handler(ConnectivityThread.getInstanceLooper()));
+        mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
+        mServiceContext.setPermission(
+                Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+    }
+
+    private void unregisterDefaultNetworkCallbacks() {
+        if (null != mDefaultNetworkCallback) {
+            mCm.unregisterNetworkCallback(mDefaultNetworkCallback);
+        }
+        if (null != mSystemDefaultNetworkCallback) {
+            mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback);
+        }
     }
 
     private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@@ -9849,12 +9932,11 @@
                 .build();
 
         // Act on ConnectivityService.setOemNetworkPreference()
-        final TestOemListenerCallback mOnSetOemNetworkPreferenceTestListener =
-                new TestOemListenerCallback();
-        mService.setOemNetworkPreference(pref, mOnSetOemNetworkPreferenceTestListener);
+        final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
+        mService.setOemNetworkPreference(pref, oemPrefListener);
 
         // Verify call returned successfully
-        mOnSetOemNetworkPreferenceTestListener.expectOnComplete();
+        oemPrefListener.expectOnComplete();
     }
 
     private static class TestOemListenerCallback implements IOnSetOemNetworkPreferenceListener {
@@ -9884,6 +9966,7 @@
         @OemNetworkPreferences.OemNetworkPreference final int networkPref =
                 OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
         final int expectedOemPrefRequestSize = 1;
+        registerDefaultNetworkCallbacks();
 
         // Setup the test process to use networkPref for their default network.
         setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -9898,6 +9981,7 @@
 
         // Verify that the active network is correct
         verifyActiveNetwork(TRANSPORT_ETHERNET);
+        // default NCs will be unregistered in tearDown
     }
 
     @Test
@@ -9905,6 +9989,7 @@
         @OemNetworkPreferences.OemNetworkPreference final int networkPref =
                 OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
         final int expectedOemPrefRequestSize = 1;
+        registerDefaultNetworkCallbacks();
 
         // Setup the test process to use networkPref for their default network.
         setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -9925,6 +10010,7 @@
                 mEthernetNetworkAgent.getNetwork());
 
         assertFalse(mCm.isActiveNetworkMetered());
+        // default NCs will be unregistered in tearDown
     }
 
     @Test
@@ -10081,7 +10167,6 @@
 
     /**
      * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
-     * @throws Exception
      */
     @Test
     public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception {
@@ -10109,9 +10194,8 @@
     }
 
     /**
-     * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID following in order:
+     * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
      * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
-     * @throws Exception
      */
     @Test
     public void testMultilayerForPreferenceOemPaidEvaluatesCorrectly()
@@ -10177,9 +10261,8 @@
     }
 
     /**
-     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK following in order:
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
      * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
-     * @throws Exception
      */
     @Test
     public void testMultilayerForPreferenceOemPaidNoFallbackEvaluatesCorrectly()
@@ -10240,10 +10323,9 @@
     }
 
     /**
-     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY following in order:
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
      * NET_CAPABILITY_OEM_PAID
      * This preference should only apply to OEM_PAID networks.
-     * @throws Exception
      */
     @Test
     public void testMultilayerForPreferenceOemPaidOnlyEvaluatesCorrectly()
@@ -10294,10 +10376,9 @@
     }
 
     /**
-     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY following in order:
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
      * NET_CAPABILITY_OEM_PRIVATE
      * This preference should only apply to OEM_PRIVATE networks.
-     * @throws Exception
      */
     @Test
     public void testMultilayerForPreferenceOemPrivateOnlyEvaluatesCorrectly()
@@ -10347,7 +10428,235 @@
                 true /* shouldDestroyNetwork */);
     }
 
-    private UidRange createUidRange(int userId) {
-        return UidRange.createForUser(UserHandle.of(userId));
+    /**
+     * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
+     * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
+     */
+    @Test
+    public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+        final int expectedDefaultRequestSize = 2;
+        final int expectedOemPrefRequestSize = 3;
+        registerDefaultNetworkCallbacks();
+
+        // The fallback as well as the OEM preference should now be tracked.
+        assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+        // Test lowest to highest priority requests.
+        // Bring up metered cellular. This will satisfy the fallback network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mCellNetworkAgent.getNetwork());
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mWiFiNetworkAgent.getNetwork(),
+                mWiFiNetworkAgent.getNetwork());
+
+        // Disconnecting unmetered Wi-Fi will put the pref on OEM_PAID and fallback on cellular.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting OEM_PAID will put both on null as it is the last network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                null);
+
+        // default NCs will be unregistered in tearDown
+    }
+
+    /**
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
+     * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
+     */
+    @Test
+    public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidNoFallbackCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+        final int expectedDefaultRequestSize = 2;
+        final int expectedOemPrefRequestSize = 2;
+        registerDefaultNetworkCallbacks();
+
+        // The fallback as well as the OEM preference should now be tracked.
+        assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+        // Test lowest to highest priority requests.
+        // Bring up metered cellular. This will satisfy the fallback network but not the pref.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mService.mNoServiceNetwork.network());
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mWiFiNetworkAgent.getNetwork(),
+                mWiFiNetworkAgent.getNetwork());
+
+        // Disconnecting unmetered Wi-Fi will put the OEM pref on OEM_PAID and fallback on cellular.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting OEM_PAID puts the fallback on null and the pref on the disconnected net.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mService.mNoServiceNetwork.network());
+
+        // default NCs will be unregistered in tearDown
+    }
+
+    /**
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
+     * NET_CAPABILITY_OEM_PAID
+     * This preference should only apply to OEM_PAID networks.
+     */
+    @Test
+    public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidOnlyCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+        final int expectedDefaultRequestSize = 2;
+        final int expectedOemPrefRequestSize = 1;
+        registerDefaultNetworkCallbacks();
+
+        // The fallback as well as the OEM preference should now be tracked.
+        assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+        // Test lowest to highest priority requests.
+        // Bring up metered cellular. This will satisfy the fallback network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mService.mNoServiceNetwork.network());
+
+        // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mWiFiNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting OEM_PAID will keep the fallback on cellular and nothing for OEM_PAID.
+        // OEM_PAID_ONLY not supporting a fallback now uses the disconnected network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mService.mNoServiceNetwork.network());
+
+        // Disconnecting cellular will put the fallback on null and the pref on disconnected.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mService.mNoServiceNetwork.network());
+
+        // default NCs will be unregistered in tearDown
+    }
+
+    /**
+     * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
+     * NET_CAPABILITY_OEM_PRIVATE
+     * This preference should only apply to OEM_PRIVATE networks.
+     */
+    @Test
+    public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPrivateOnlyCorrectly()
+            throws Exception {
+        @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+                OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+        setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+        final int expectedDefaultRequestSize = 2;
+        final int expectedOemPrefRequestSize = 1;
+        registerDefaultNetworkCallbacks();
+
+        // The fallback as well as the OEM preference should now be tracked.
+        assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+        // Test lowest to highest priority requests.
+        // Bring up metered cellular. This will satisfy the fallback network.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mService.mNoServiceNetwork.network());
+
+        // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
+        startOemManagedNetwork(false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mWiFiNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mEthernetNetworkAgent.getNetwork());
+
+        // Disconnecting OEM_PRIVATE will keep the fallback on cellular.
+        // OEM_PRIVATE_ONLY not supporting a fallback now uses to the disconnected network.
+        stopOemManagedNetwork();
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                mCellNetworkAgent.getNetwork(),
+                mService.mNoServiceNetwork.network());
+
+        // Disconnecting cellular will put the fallback on null and pref on disconnected.
+        setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+        verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+                null,
+                mService.mNoServiceNetwork.network());
+
+        // default NCs will be unregistered in tearDown
     }
 }
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index f5b85ca..5760211 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -22,6 +22,8 @@
 import static android.net.NetworkCapabilities.MIN_TRANSPORT;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -164,7 +166,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
-                InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+                        InetAddress.parseNumericAddress("4.4.4.4"), "",
+                        VALIDATION_RESULT_SUCCESS));
         LinkProperties fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertFalse(fixedLp.isPrivateDnsActive());
@@ -204,7 +207,8 @@
         // Validate one.
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
+                        InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com",
+                        VALIDATION_RESULT_SUCCESS));
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
@@ -212,7 +216,8 @@
         // Validate the 2nd one.
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
+                        InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com",
+                        VALIDATION_RESULT_SUCCESS));
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertEquals(Arrays.asList(
@@ -232,7 +237,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -245,7 +251,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -253,7 +260,8 @@
         // Validation event has untracked ipAddress
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+                        InetAddress.parseNumericAddress("4.4.4.4"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -261,8 +269,8 @@
         // Validation event has untracked hostname
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
-                true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -270,7 +278,8 @@
         // Validation event failed
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", false));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_FAILURE));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -279,7 +288,7 @@
         mDnsManager.removeNetwork(new Network(TEST_NETID));
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "", VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -293,7 +302,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -398,7 +408,8 @@
         mDnsManager.updatePrivateDns(network, mDnsManager.getPrivateDnsConfig());
         mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
         mDnsManager.updatePrivateDnsValidation(
-                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "", true));
+                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
         assertTrue(privateDnsCfg.useTls);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 52cb836..a913673 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -41,7 +41,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
 import android.os.Binder;
-import android.os.INetworkManagementService;
 import android.text.format.DateUtils;
 
 import androidx.test.filters.SmallTest;
@@ -74,7 +73,6 @@
     @Mock ConnectivityService mConnService;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
-    @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
@@ -358,8 +356,8 @@
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
                 new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
-                mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
-                Binder.getCallingUid(), mQosCallbackTracker);
+                mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+                mQosCallbackTracker);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index 4f65b67..5f56e25 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -36,7 +36,6 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkInfo;
 import android.os.Handler;
-import android.os.INetworkManagementService;
 import android.os.test.TestLooper;
 
 import androidx.test.filters.SmallTest;
@@ -67,7 +66,6 @@
     @Mock ConnectivityService mConnectivity;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
-    @Mock INetworkManagementService mNms;
     @Mock NetworkAgentInfo mNai;
 
     TestLooper mLooper;
@@ -75,7 +73,7 @@
     NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
+        return new Nat464Xlat(mNai, mNetd, mDnsResolver) {
             @Override protected int getNetId() {
                 return NETID;
             }
@@ -206,7 +204,6 @@
         // Start clat.
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // Stacked interface up notification arrives.
@@ -225,7 +222,6 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
-        verify(mNms).unregisterObserver(eq(nat));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
@@ -235,7 +231,7 @@
         nat.interfaceRemoved(STACKED_IFACE);
         mLooper.dispatchNext();
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
@@ -346,7 +342,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // Stacked interface up notification arrives.
@@ -365,7 +360,6 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -374,7 +368,7 @@
         // ConnectivityService stops clat: no-op.
         nat.stop();
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
@@ -386,7 +380,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
@@ -394,7 +387,6 @@
         nat.stop();
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
@@ -408,7 +400,7 @@
 
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
@@ -430,7 +422,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
@@ -438,11 +429,10 @@
         nat.stop();
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 7489a0f..b8f7fbc 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -91,7 +91,6 @@
 import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.KeyStore;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Range;
@@ -196,7 +195,7 @@
     @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
     @Mock private ConnectivityManager mConnectivityManager;
     @Mock private IpSecService mIpSecService;
-    @Mock private KeyStore mKeyStore;
+    @Mock private VpnProfileStore mVpnProfileStore;
     private final VpnProfile mVpnProfile;
 
     private IpSecManager mIpSecManager;
@@ -333,17 +332,17 @@
         assertFalse(vpn.getLockdown());
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList(), mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList(), mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertTrue(vpn.getLockdown());
 
         // Remove always-on configuration.
-        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList(), mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
         assertFalse(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
     }
@@ -354,17 +353,17 @@
         final UidRange user = PRI_USER_RANGE;
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
 
         // Switch to another app.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -382,14 +381,14 @@
 
         // Set always-on with lockdown and allow app PKGS[2] from lockdown.
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore));
+                PKGS[1], true, Collections.singletonList(PKGS[2])));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
         // Change allowed app list to PKGS[3].
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore));
+                PKGS[1], true, Collections.singletonList(PKGS[3])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
@@ -400,7 +399,7 @@
 
         // Change the VPN app.
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore));
+                PKGS[0], true, Collections.singletonList(PKGS[3])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
@@ -411,7 +410,7 @@
         }));
 
         // Remove the list of allowed packages.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
@@ -422,7 +421,7 @@
 
         // Add the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore));
+                PKGS[0], true, Collections.singletonList(PKGS[1])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
         }));
@@ -433,12 +432,12 @@
 
         // Try allowing a package with a comma, should be rejected.
         assertFalse(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore));
+                PKGS[0], true, Collections.singletonList("a.b,c.d")));
 
         // Pass a non-existent packages in the allowlist, they (and only they) should be ignored.
         // allowed package should change from PGKS[1] to PKGS[2].
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore));
+                PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -525,22 +524,22 @@
                 .thenReturn(Collections.singletonList(resInfo));
 
         // null package name should return false
-        assertFalse(vpn.isAlwaysOnPackageSupported(null, mKeyStore));
+        assertFalse(vpn.isAlwaysOnPackageSupported(null));
 
         // Pre-N apps are not supported
         appInfo.targetSdkVersion = VERSION_CODES.M;
-        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
+        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
 
         // N+ apps are supported by default
         appInfo.targetSdkVersion = VERSION_CODES.N;
-        assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
+        assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
 
         // Apps that opt out explicitly are not supported
         appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
         Bundle metaData = new Bundle();
         metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
         svcInfo.metaData = metaData;
-        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
+        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
     }
 
     @Test
@@ -556,7 +555,7 @@
         order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
 
         // Start showing a notification for disconnected once always-on.
-        vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore);
+        vpn.setAlwaysOnPackage(PKGS[0], false, null);
         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
 
         // Stop showing the notification once connected.
@@ -568,7 +567,7 @@
         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
 
         // Notification should be cleared after unsetting always-on package.
-        vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+        vpn.setAlwaysOnPackage(null, false, null);
         order.verify(mNotificationManager).cancel(anyString(), anyInt());
     }
 
@@ -608,15 +607,13 @@
     }
 
     private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
-        assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore));
+        assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile));
 
         // The profile should always be stored, whether or not consent has been previously granted.
-        verify(mKeyStore)
+        verify(mVpnProfileStore)
                 .put(
                         eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
-                        eq(mVpnProfile.encode()),
-                        eq(Process.SYSTEM_UID),
-                        eq(0));
+                        eq(mVpnProfile.encode()));
 
         for (final String checkedOpStr : checkedOps) {
             verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
@@ -671,7 +668,7 @@
         bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
 
         try {
-            vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile, mKeyStore);
+            vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile);
             fail("Expected IAE due to profile size");
         } catch (IllegalArgumentException expected) {
         }
@@ -684,7 +681,7 @@
                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
         try {
-            vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore);
+            vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile);
             fail("Expected SecurityException due to restricted user");
         } catch (SecurityException expected) {
         }
@@ -694,10 +691,10 @@
     public void testDeleteVpnProfile() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks();
 
-        vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
+        vpn.deleteVpnProfile(TEST_VPN_PKG);
 
-        verify(mKeyStore)
-                .delete(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), eq(Process.SYSTEM_UID));
+        verify(mVpnProfileStore)
+                .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
     }
 
     @Test
@@ -707,7 +704,7 @@
                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
         try {
-            vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.deleteVpnProfile(TEST_VPN_PKG);
             fail("Expected SecurityException due to restricted user");
         } catch (SecurityException expected) {
         }
@@ -717,24 +714,24 @@
     public void testGetVpnProfilePrivileged() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks();
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(new VpnProfile("").encode());
 
-        vpn.getVpnProfilePrivileged(TEST_VPN_PKG, mKeyStore);
+        vpn.getVpnProfilePrivileged(TEST_VPN_PKG);
 
-        verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
     }
 
     @Test
     public void testStartVpnProfile() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(mVpnProfile.encode());
 
-        vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+        vpn.startVpnProfile(TEST_VPN_PKG);
 
-        verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
         verify(mAppOps)
                 .noteOpNoThrow(
                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
@@ -748,10 +745,10 @@
     public void testStartVpnProfileVpnServicePreconsented() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(mVpnProfile.encode());
 
-        vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+        vpn.startVpnProfile(TEST_VPN_PKG);
 
         // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
         verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
@@ -763,7 +760,7 @@
         final Vpn vpn = createVpnAndSetupUidChecks();
 
         try {
-            vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.startVpnProfile(TEST_VPN_PKG);
             fail("Expected failure due to no user consent");
         } catch (SecurityException expected) {
         }
@@ -780,22 +777,22 @@
                 TEST_VPN_PKG, null /* attributionTag */, null /* message */);
 
         // Keystore should never have been accessed.
-        verify(mKeyStore, never()).get(any());
+        verify(mVpnProfileStore, never()).get(any());
     }
 
     @Test
     public void testStartVpnProfileMissingProfile() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
 
         try {
-            vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.startVpnProfile(TEST_VPN_PKG);
             fail("Expected failure due to missing profile");
         } catch (IllegalArgumentException expected) {
         }
 
-        verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
+        verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
         verify(mAppOps)
                 .noteOpNoThrow(
                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
@@ -812,7 +809,7 @@
                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
         try {
-            vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.startVpnProfile(TEST_VPN_PKG);
             fail("Expected SecurityException due to restricted user");
         } catch (SecurityException expected) {
         }
@@ -938,9 +935,9 @@
     }
 
     private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
-        assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null));
 
-        verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
         verify(mAppOps).setMode(
                 eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
                 eq(AppOpsManager.MODE_ALLOWED));
@@ -963,11 +960,11 @@
         final int uid = Process.myUid() + 1;
         when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
                 .thenReturn(uid);
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(mVpnProfile.encode());
 
         setAndVerifyAlwaysOnPackage(vpn, uid, false);
-        assertTrue(vpn.startAlwaysOnVpn(mKeyStore));
+        assertTrue(vpn.startAlwaysOnVpn());
 
         // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
         // a subsequent CL.
@@ -984,7 +981,7 @@
                         InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
         lp.addRoute(defaultRoute);
 
-        vpn.startLegacyVpn(vpnProfile, mKeyStore, EGRESS_NETWORK, lp);
+        vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp);
         return vpn;
     }
 
@@ -1186,7 +1183,7 @@
                 .thenReturn(asUserContext);
         final TestLooper testLooper = new TestLooper();
         final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
-                mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+                mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
         verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
                 provider -> provider.getName().contains("VpnNetworkProvider")
         ));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 54d6fb9..9334e2c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,9 +19,7 @@
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkIdentity.OEM_PAID;
 import static android.net.NetworkIdentity.OEM_PRIVATE;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -86,7 +84,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -286,7 +284,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -329,7 +327,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -403,7 +401,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -444,7 +442,7 @@
     public void testUidStatsAcrossNetworks() throws Exception {
         // pretend first mobile network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -475,7 +473,7 @@
         // disappearing, to verify we don't count backwards.
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectDefaultSettings();
-        states = new NetworkState[] {buildMobile3gState(IMSI_2)};
+        states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_2)};
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
@@ -519,7 +517,7 @@
     public void testUidRemovedIsMoved() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -583,7 +581,8 @@
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
         final NetworkTemplate template5g =
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
 
         // 3G network comes online.
         expectNetworkStatsSummary(buildEmptyStats());
@@ -673,7 +672,8 @@
                 METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO);
 
         // OEM_PAID network comes online.
-        NetworkState[] states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
+                buildOemManagedMobileState(IMSI_1, false,
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -688,7 +688,7 @@
         forcePollAndWaitForIdle();
 
         // OEM_PRIVATE network comes online.
-        states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -703,7 +703,7 @@
         forcePollAndWaitForIdle();
 
         // OEM_PAID + OEM_PRIVATE network comes online.
-        states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
                 new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
                           NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
         expectNetworkStatsSummary(buildEmptyStats());
@@ -719,7 +719,7 @@
         forcePollAndWaitForIdle();
 
         // OEM_NONE network comes online.
-        states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
         mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
@@ -771,7 +771,7 @@
     public void testSummaryForAllUid() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -830,7 +830,7 @@
     public void testDetailedUidStats() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -871,9 +871,9 @@
         final String stackedIface = "stacked-test0";
         final LinkProperties stackedProp = new LinkProperties();
         stackedProp.setInterfaceName(stackedIface);
-        final NetworkState wifiState = buildWifiState();
+        final NetworkStateSnapshot wifiState = buildWifiState();
         wifiState.linkProperties.addStackedLink(stackedProp);
-        NetworkState[] states = new NetworkState[] {wifiState};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {wifiState};
 
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -929,7 +929,7 @@
     public void testForegroundBackground() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -986,8 +986,8 @@
     public void testMetered() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states =
-                new NetworkState[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
+        NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1026,8 +1026,8 @@
     public void testRoaming() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states =
-            new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
+        NetworkStateSnapshot[] states =
+            new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1065,7 +1065,8 @@
     public void testTethering() throws Exception {
         // pretend first mobile network comes online
         expectDefaultSettings();
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1122,7 +1123,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1220,8 +1221,8 @@
     public void testStatsProviderUpdateStats() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
-        final NetworkState[] states =
-                new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1282,8 +1283,8 @@
     public void testStatsProviderSetAlert() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
-        NetworkState[] states =
-                new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
+        NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
         mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
@@ -1326,7 +1327,8 @@
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN);
         final NetworkTemplate templateAll =
                 buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
 
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1401,7 +1403,7 @@
     public void testOperationCount_nonDefault_traffic() throws Exception {
         // Pretend mobile network comes online, but wifi is the default network.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[]{
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
                 buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
         expectNetworkStatsUidDetail(buildEmptyStats());
         mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
@@ -1489,7 +1491,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
     }
 
-    private String getActiveIface(NetworkState... states) throws Exception {
+    private String getActiveIface(NetworkStateSnapshot... states) throws Exception {
         if (states == null || states.length == 0 || states[0].linkProperties == null) {
             return null;
         }
@@ -1565,11 +1567,11 @@
         assertEquals("unexpected operations", operations, entry.operations);
     }
 
-    private static NetworkState buildWifiState() {
+    private static NetworkStateSnapshot buildWifiState() {
         return buildWifiState(false, TEST_IFACE);
     }
 
-    private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) {
+    private static NetworkStateSnapshot buildWifiState(boolean isMetered, @NonNull String iface) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(iface);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1577,35 +1579,30 @@
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         capabilities.setSSID(TEST_SSID);
-        return new NetworkState(TYPE_WIFI, prop, capabilities, WIFI_NETWORK, null);
+        return new NetworkStateSnapshot(WIFI_NETWORK, capabilities, prop, null, TYPE_WIFI);
     }
 
-    private static NetworkState buildMobile3gState(String subscriberId) {
+    private static NetworkStateSnapshot buildMobile3gState(String subscriberId) {
         return buildMobile3gState(subscriberId, false /* isRoaming */);
     }
 
-    private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
+    private static NetworkStateSnapshot buildMobile3gState(String subscriberId, boolean isRoaming) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+        return new NetworkStateSnapshot(
+                MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
     }
 
     private NetworkStats buildEmptyStats() {
         return new NetworkStats(getElapsedRealtime(), 0);
     }
 
-    private static NetworkState buildVpnState() {
-        final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(TUN_IFACE);
-        return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null);
-    }
-
-    private static NetworkState buildOemManagedMobileState(String subscriberId, boolean isRoaming,
-                int[] oemNetCapabilities) {
+    private static NetworkStateSnapshot buildOemManagedMobileState(
+            String subscriberId, boolean isRoaming, int[] oemNetCapabilities) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1615,7 +1612,8 @@
             capabilities.setCapability(nc, true);
         }
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+        return new NetworkStateSnapshot(MOBILE_NETWORK, capabilities, prop, subscriberId,
+                TYPE_MOBILE);
     }
 
     private long getElapsedRealtime() {
diff --git a/tests/vcn/assets/self-signed-ca.pem b/tests/vcn/assets/self-signed-ca.pem
new file mode 100644
index 0000000..5135ea7
--- /dev/null
+++ b/tests/vcn/assets/self-signed-ca.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
+BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p
+ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG
+EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk
+Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy
+Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR
+Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp
+99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ
+1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc
+g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5
+JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB
+AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb
+QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05
+yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6
+Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P
+t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8
+u4r44fj4/9W0Zeooav5Yoh1q
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 66590c9..7515971 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -203,9 +203,6 @@
         IVcnStatusCallback cbBinder =
                 new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
 
-        cbBinder.onEnteredSafeMode();
-        verify(mMockStatusCallback).onEnteredSafeMode();
-
         cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
         verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
 
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
new file mode 100644
index 0000000..bc8e9d3
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static android.telephony.TelephonyManager.APPTYPE_USIM;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.eap.EapSessionConfig;
+import android.os.PersistableBundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EapSessionConfigUtilsTest {
+    private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+    private static final String USERNAME = "username";
+    private static final String PASSWORD = "password";
+    private static final int SUB_ID = 1;
+    private static final String NETWORK_NAME = "android.net";
+    private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
+
+    private EapSessionConfig.Builder createBuilderWithId() {
+        return new EapSessionConfig.Builder().setEapIdentity(EAP_ID);
+    }
+
+    private static void verifyPersistableBundleEncodeDecodeIsLossless(EapSessionConfig config) {
+        final PersistableBundle bundle = EapSessionConfigUtils.toPersistableBundle(config);
+        final EapSessionConfig resultConfig = EapSessionConfigUtils.fromPersistableBundle(bundle);
+
+        assertEquals(config, resultConfig);
+    }
+
+    @Test
+    public void testSetEapMsChapV2EncodeDecodeIsLossless() throws Exception {
+        final EapSessionConfig config =
+                createBuilderWithId().setEapMsChapV2Config(USERNAME, PASSWORD).build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(config);
+    }
+
+    @Test
+    public void testSetEapSimEncodeDecodeIsLossless() throws Exception {
+        final EapSessionConfig config =
+                createBuilderWithId().setEapSimConfig(SUB_ID, APPTYPE_USIM).build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(config);
+    }
+
+    @Test
+    public void testSetEapAkaEncodeDecodeIsLossless() throws Exception {
+        final EapSessionConfig config =
+                createBuilderWithId().setEapAkaConfig(SUB_ID, APPTYPE_USIM).build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(config);
+    }
+
+    @Test
+    public void testSetEapAkaPrimeEncodeDecodeIsLossless() throws Exception {
+        final EapSessionConfig config =
+                createBuilderWithId()
+                        .setEapAkaPrimeConfig(
+                                SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
+                        .build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(config);
+    }
+
+    @Test
+    public void testSetEapTtlsEncodeDecodeIsLossless() throws Exception {
+        final InputStream inputStream =
+                InstrumentationRegistry.getContext()
+                        .getResources()
+                        .getAssets()
+                        .open("self-signed-ca.pem");
+        final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        final X509Certificate trustedCa =
+                (X509Certificate) factory.generateCertificate(inputStream);
+
+        final EapSessionConfig innerConfig =
+                new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
+
+        final EapSessionConfig config =
+                new EapSessionConfig.Builder().setEapTtlsConfig(trustedCa, innerConfig).build();
+
+        verifyPersistableBundleEncodeDecodeIsLossless(config);
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
new file mode 100644
index 0000000..4f3930f
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeIdentification;
+import android.net.ipsec.ike.IkeIpv4AddrIdentification;
+import android.net.ipsec.ike.IkeIpv6AddrIdentification;
+import android.net.ipsec.ike.IkeKeyIdIdentification;
+import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+
+import javax.security.auth.x500.X500Principal;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeIdentificationUtilsTest {
+    private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) {
+        final PersistableBundle bundle = IkeIdentificationUtils.toPersistableBundle(id);
+        final IkeIdentification result = IkeIdentificationUtils.fromPersistableBundle(bundle);
+
+        assertEquals(result, id);
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIpv4AddressId() throws Exception {
+        final Inet4Address ipv4Address = (Inet4Address) InetAddress.getByName("192.0.2.100");
+        verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv4AddrIdentification(ipv4Address));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIpv6AddressId() throws Exception {
+        final Inet6Address ipv6Address = (Inet6Address) InetAddress.getByName("2001:db8:2::100");
+        verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv6AddrIdentification(ipv6Address));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeRfc822AddrId() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(new IkeFqdnIdentification("ike.android.net"));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeFqdnId() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeRfc822AddrIdentification("androidike@example.com"));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeKeyId() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeKeyIdIdentification("androidIkeKeyId".getBytes()));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeDerAsn1DnId() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeDerAsn1DnIdentification(
+                        new X500Principal("CN=small.server.test.android.net, O=Android, C=US")));
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
new file mode 100644
index 0000000..28cf38a
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeTrafficSelectorUtilsTest {
+    private static final int START_PORT = 16;
+    private static final int END_PORT = 65520;
+
+    private static final InetAddress IPV4_START_ADDRESS =
+            InetAddresses.parseNumericAddress("192.0.2.100");
+    private static final InetAddress IPV4_END_ADDRESS =
+            InetAddresses.parseNumericAddress("192.0.2.101");
+
+    private static final InetAddress IPV6_START_ADDRESS =
+            InetAddresses.parseNumericAddress("2001:db8:2::100");
+    private static final InetAddress IPV6_END_ADDRESS =
+            InetAddresses.parseNumericAddress("2001:db8:2::101");
+
+    private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeTrafficSelector ts) {
+        final PersistableBundle bundle = IkeTrafficSelectorUtils.toPersistableBundle(ts);
+        final IkeTrafficSelector resultTs = IkeTrafficSelectorUtils.fromPersistableBundle(bundle);
+        assertEquals(ts, resultTs);
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIsLosslessIpv4Ts() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeTrafficSelector(START_PORT, END_PORT, IPV4_START_ADDRESS, IPV4_END_ADDRESS));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIsLosslessIpv6Ts() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeTrafficSelector(START_PORT, END_PORT, IPV6_START_ADDRESS, IPV6_END_ADDRESS));
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
new file mode 100644
index 0000000..8ae8692
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.SaProposal;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SaProposalUtilsTest {
+    @Test
+    public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception {
+        final IkeSaProposal proposal =
+                new IkeSaProposal.Builder()
+                        .addEncryptionAlgorithm(
+                                SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
+                        .addEncryptionAlgorithm(
+                                SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
+                        .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
+                        .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+                        .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
+                        .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
+                        .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+                        .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
+                        .build();
+
+        final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal);
+        final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle);
+
+        assertEquals(proposal, resultProposal);
+    }
+
+    /** Package private so that TunnelModeChildSessionParamsUtilsTest can use it */
+    static ChildSaProposal buildTestChildSaProposal() {
+        return new ChildSaProposal.Builder()
+                .addEncryptionAlgorithm(
+                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+                .addEncryptionAlgorithm(
+                        SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_192)
+                .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+                .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP)
+                .build();
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIsLosslessChildProposal() throws Exception {
+        final ChildSaProposal proposal = buildTestChildSaProposal();
+
+        final PersistableBundle bundle = ChildSaProposalUtils.toPersistableBundle(proposal);
+        final SaProposal resultProposal = ChildSaProposalUtils.fromPersistableBundle(bundle);
+
+        assertEquals(proposal, resultProposal);
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
new file mode 100644
index 0000000..b3cd0ab
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunnelModeChildSessionParamsUtilsTest {
+    private TunnelModeChildSessionParams.Builder createBuilderMinimum() {
+        final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal();
+        return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal);
+    }
+
+    private static void verifyPersistableBundleEncodeDecodeIsLossless(
+            TunnelModeChildSessionParams params) {
+        final PersistableBundle bundle =
+                TunnelModeChildSessionParamsUtils.toPersistableBundle(params);
+        final TunnelModeChildSessionParams result =
+                TunnelModeChildSessionParamsUtils.fromPersistableBundle(bundle);
+
+        assertEquals(params, result);
+    }
+
+    @Test
+    public void testMinimumParamsEncodeDecodeIsLossless() throws Exception {
+        final TunnelModeChildSessionParams sessionParams = createBuilderMinimum().build();
+        verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+    }
+
+    @Test
+    public void testSetTsEncodeDecodeIsLossless() throws Exception {
+        final IkeTrafficSelector tsInbound =
+                new IkeTrafficSelector(
+                        16,
+                        65520,
+                        InetAddresses.parseNumericAddress("192.0.2.100"),
+                        InetAddresses.parseNumericAddress("192.0.2.101"));
+        final IkeTrafficSelector tsOutbound =
+                new IkeTrafficSelector(
+                        32,
+                        256,
+                        InetAddresses.parseNumericAddress("192.0.2.200"),
+                        InetAddresses.parseNumericAddress("192.0.2.255"));
+
+        final TunnelModeChildSessionParams sessionParams =
+                createBuilderMinimum()
+                        .addInboundTrafficSelectors(tsInbound)
+                        .addOutboundTrafficSelectors(tsOutbound)
+                        .build();
+        verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+    }
+
+    @Test
+    public void testSetLifetimesEncodeDecodeIsLossless() throws Exception {
+        final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(3L);
+        final int softLifetime = (int) TimeUnit.HOURS.toSeconds(1L);
+
+        final TunnelModeChildSessionParams sessionParams =
+                createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build();
+        verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+    }
+
+    @Test
+    public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception {
+        final int ipv6PrefixLen = 64;
+        final Inet4Address ipv4Address =
+                (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100");
+        final Inet6Address ipv6Address =
+                (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
+
+        final TunnelModeChildSessionParams sessionParams =
+                createBuilderMinimum()
+                        .addInternalAddressRequest(AF_INET)
+                        .addInternalAddressRequest(AF_INET6)
+                        .addInternalAddressRequest(ipv4Address)
+                        .addInternalAddressRequest(ipv6Address, ipv6PrefixLen)
+                        .addInternalDnsServerRequest(AF_INET)
+                        .addInternalDnsServerRequest(AF_INET6)
+                        .addInternalDhcpServerRequest(AF_INET)
+                        .build();
+        verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 9b500a7..73a6b88 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -100,6 +100,8 @@
 public class VcnManagementServiceTest {
     private static final String TEST_PACKAGE_NAME =
             VcnManagementServiceTest.class.getPackage().getName();
+    private static final String TEST_CB_PACKAGE_NAME =
+            VcnManagementServiceTest.class.getPackage().getName() + ".callback";
     private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
     private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
     private static final VcnConfig TEST_VCN_CONFIG;
@@ -288,6 +290,14 @@
 
     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
             Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) {
+        return triggerSubscriptionTrackerCbAndGetSnapshot(
+                activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */);
+    }
+
+    private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+            Set<ParcelUuid> activeSubscriptionGroups,
+            Map<Integer, ParcelUuid> subIdToGroupMap,
+            boolean hasCarrierPrivileges) {
         final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
         doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
 
@@ -295,7 +305,7 @@
                 (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
                         ? Collections.emptySet()
                         : Collections.singleton(TEST_PACKAGE_NAME);
-        doReturn(true)
+        doReturn(hasCarrierPrivileges)
                 .when(snapshot)
                 .packageHasPermissionsForSubscriptionGroup(
                         argThat(val -> activeSubscriptionGroups.contains(val)),
@@ -549,13 +559,6 @@
         mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
     }
 
-    private void setUpVcnSubscription(int subId, ParcelUuid subGroup) {
-        mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
-
-        triggerSubscriptionTrackerCbAndGetSnapshot(
-                Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup));
-    }
-
     private void verifyMergedNetworkCapabilities(
             NetworkCapabilities mergedCapabilities,
             @Transport int transportType,
@@ -573,9 +576,23 @@
     }
 
     private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
-        setUpVcnSubscription(subId, subGrp);
+        setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */);
+    }
+
+    private void setupSubscriptionAndStartVcn(
+            int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
+        mVcnMgmtSvc.systemReady();
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                Collections.singleton(subGrp),
+                Collections.singletonMap(subId, subGrp),
+                hasCarrierPrivileges);
+
         final Vcn vcn = startAndGetVcnInstance(subGrp);
         doReturn(isVcnActive).when(vcn).isActive();
+
+        doReturn(true)
+                .when(mLocationPermissionChecker)
+                .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
     }
 
     private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
@@ -721,7 +738,7 @@
         verify(mMockPolicyListener).onPolicyChanged();
     }
 
-    private void verifyVcnCallback(
+    private void triggerVcnSafeMode(
             @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
             throws Exception {
         verify(mMockDeps)
@@ -732,20 +749,20 @@
                         eq(snapshot),
                         mVcnCallbackCaptor.capture());
 
-        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
-
         VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
         vcnCallback.onEnteredSafeMode();
-
-        verify(mMockPolicyListener).onPolicyChanged();
     }
 
     @Test
-    public void testVcnCallbackOnEnteredSafeMode() throws Exception {
+    public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
         TelephonySubscriptionSnapshot snapshot =
                 triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
 
-        verifyVcnCallback(TEST_UUID_1, snapshot);
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        triggerVcnSafeMode(TEST_UUID_1, snapshot);
+
+        verify(mMockPolicyListener).onPolicyChanged();
     }
 
     private void triggerVcnStatusCallbackOnEnteredSafeMode(
@@ -758,6 +775,9 @@
         TelephonySubscriptionSnapshot snapshot =
                 triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup));
 
+        setupSubscriptionAndStartVcn(
+                TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
+
         doReturn(hasPermissionsforSubGroup)
                 .when(snapshot)
                 .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
@@ -768,10 +788,7 @@
 
         mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
 
-        // Trigger systemReady() to set up LocationPermissionChecker
-        mVcnMgmtSvc.systemReady();
-
-        verifyVcnCallback(subGroup, snapshot);
+        triggerVcnSafeMode(subGroup, snapshot);
     }
 
     @Test
@@ -825,6 +842,83 @@
         assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
         assertEquals(TEST_UID, cbInfo.mUid);
         verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+    }
+
+    @Test
+    public void testRegisterVcnStatusCallback_MissingPermission() throws Exception {
+        setupSubscriptionAndStartVcn(
+                TEST_SUBSCRIPTION_ID,
+                TEST_UUID_1,
+                true /* isActive */,
+                false /* hasCarrierPrivileges */);
+
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+    }
+
+    @Test
+    public void testRegisterVcnStatusCallback_VcnInactive() throws Exception {
+        setupSubscriptionAndStartVcn(
+                TEST_SUBSCRIPTION_ID,
+                TEST_UUID_1,
+                true /* isActive */,
+                true /* hasCarrierPrivileges */);
+
+        // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
+        // timeout so the VCN goes inactive.
+        final TelephonySubscriptionSnapshot snapshot =
+                triggerSubscriptionTrackerCbAndGetSnapshot(
+                        Collections.singleton(TEST_UUID_1),
+                        Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
+                        false /* hasCarrierPrivileges */);
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+        mTestLooper.dispatchAll();
+
+        // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE
+        // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE
+        // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without
+        // reactivating the VCN.
+        doReturn(true)
+                .when(snapshot)
+                .packageHasPermissionsForSubscriptionGroup(
+                        eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME));
+        doReturn(true)
+                .when(mLocationPermissionChecker)
+                .checkLocationPermission(eq(TEST_CB_PACKAGE_NAME), any(), eq(TEST_UID), any());
+
+        mVcnMgmtSvc.registerVcnStatusCallback(
+                TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE);
+    }
+
+    @Test
+    public void testRegisterVcnStatusCallback_VcnActive() throws Exception {
+        setupSubscriptionAndStartVcn(
+                TEST_SUBSCRIPTION_ID,
+                TEST_UUID_1,
+                true /* isActive */,
+                true /* hasCarrierPrivileges */);
+
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+    }
+
+    @Test
+    public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception {
+        setupSubscriptionAndStartVcn(
+                TEST_SUBSCRIPTION_ID,
+                TEST_UUID_1,
+                false /* isActive */,
+                true /* hasCarrierPrivileges */);
+
+        mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+        verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
     }
 
     @Test(expected = IllegalStateException.class)
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 69c21b9..69b2fb1 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -36,6 +36,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
@@ -143,11 +144,18 @@
                 .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
         mTestLooper.dispatchAll();
 
+        verify(mIpSecSvc, times(2))
+                .setNetworkForTunnelInterface(
+                        eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
+                        eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
+                        any());
+
         for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
             verify(mIpSecSvc)
                     .applyTunnelModeTransform(
                             eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
         }
+
         assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
     }
 
@@ -290,4 +298,22 @@
         verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
                 new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR);
     }
+
+    @Test
+    public void testTeardown() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isQuitting());
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 17ae19e..d07d2cf 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -19,6 +19,8 @@
 import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -111,4 +113,22 @@
     public void testSafeModeTimeoutNotifiesCallback() {
         verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
     }
+
+    @Test
+    public void testTeardown() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isQuitting());
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 9ea641f..5f27fab 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -21,9 +21,12 @@
 import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.net.IpSecManager;
@@ -54,7 +57,7 @@
     }
 
     @Test
-    public void testEnterWhileNotRunningTriggersQuit() throws Exception {
+    public void testEnterWhileQuittingTriggersQuit() throws Exception {
         final VcnGatewayConnection vgc =
                 new VcnGatewayConnection(
                         mVcnContext,
@@ -64,7 +67,7 @@
                         mGatewayStatusCallback,
                         mDeps);
 
-        vgc.setIsRunning(false);
+        vgc.setIsQuitting(true);
         vgc.transitionTo(vgc.mDisconnectedState);
         mTestLooper.dispatchAll();
 
@@ -101,5 +104,18 @@
         assertNull(mGatewayConnection.getCurrentState());
         verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
         verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+        assertTrue(mGatewayConnection.isQuitting());
+        verify(mGatewayStatusCallback).onQuit();
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+        verify(mGatewayStatusCallback, never()).onQuit();
+        // No safe mode timer changes expected.
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 7385204..661e03a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -18,6 +18,8 @@
 
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -79,10 +81,20 @@
         // Should do nothing; already tearing down.
         assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
         verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+        assertTrue(mGatewayConnection.isQuitting());
     }
 
     @Test
     public void testSafeModeTimeoutNotifiesCallback() {
         verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
     }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 5b0850b..85a0277 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -17,6 +17,9 @@
 package com.android.server.vcn;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -96,4 +99,22 @@
     public void testSafeModeTimeoutNotifiesCallback() {
         verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
     }
+
+    @Test
+    public void testTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertNull(mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isQuitting());
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 9d33682..3dd710a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -16,6 +16,10 @@
 
 package com.android.server.vcn;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.mockito.Matchers.any;
@@ -33,6 +37,7 @@
 import android.net.vcn.VcnGatewayConnectionConfigTest;
 import android.os.ParcelUuid;
 import android.os.test.TestLooper;
+import android.util.ArraySet;
 
 import com.android.server.VcnManagementService.VcnCallback;
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -51,6 +56,11 @@
     private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
     private static final int NETWORK_SCORE = 0;
     private static final int PROVIDER_ID = 5;
+    private static final int[][] TEST_CAPS =
+            new int[][] {
+                new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS},
+                new int[] {NET_CAPABILITY_DUN}
+            };
 
     private Context mContext;
     private VcnContext mVcnContext;
@@ -91,13 +101,12 @@
         mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
 
         final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext);
-        for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+        for (final int[] caps : TEST_CAPS) {
             configBuilder.addGatewayConnectionConfig(
-                    VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability));
+                    VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps));
         }
-        configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig());
-        mConfig = configBuilder.build();
 
+        mConfig = configBuilder.build();
         mVcn =
                 new Vcn(
                         mVcnContext,
@@ -130,8 +139,7 @@
     @Test
     public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
-        startVcnGatewayWithCapabilities(
-                requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS);
+        startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
 
         final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
         assertFalse(gatewayConnections.isEmpty());
@@ -153,10 +161,19 @@
         for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
             startVcnGatewayWithCapabilities(requestListener, capability);
         }
+    }
 
-        // Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp.
-        // Expect one VcnGatewayConnection per capability.
-        final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length;
+    private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
+        for (final int[] caps : TEST_CAPS) {
+            startVcnGatewayWithCapabilities(requestListener, caps);
+        }
+    }
+
+    public Set<VcnGatewayConnection> startGatewaysAndGetGatewayConnections(
+            NetworkRequestListener requestListener) {
+        triggerVcnRequestListeners(requestListener);
+
+        final int numExpectedGateways = TEST_CAPS.length;
 
         final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
         assertEquals(numExpectedGateways, gatewayConnections.size());
@@ -168,7 +185,16 @@
                         any(),
                         mGatewayStatusCallbackCaptor.capture());
 
-        // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down
+        return gatewayConnections;
+    }
+
+    @Test
+    public void testGatewayEnteringSafemodeNotifiesVcn() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        final Set<VcnGatewayConnection> gatewayConnections =
+                startGatewaysAndGetGatewayConnections(requestListener);
+
+        // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
         // all Gateways
         final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
         statusCallback.onEnteredSafeMode();
@@ -181,4 +207,31 @@
         verify(mVcnNetworkProvider).unregisterListener(requestListener);
         verify(mVcnCallback).onEnteredSafeMode();
     }
+
+    @Test
+    public void testGatewayQuit() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        final Set<VcnGatewayConnection> gatewayConnections =
+                new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+
+        final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+        statusCallback.onQuit();
+        mTestLooper.dispatchAll();
+
+        // Verify that the VCN requests the networkRequests be resent
+        assertEquals(1, mVcn.getVcnGatewayConnections().size());
+        verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+
+        // Verify that the VcnGatewayConnection is restarted
+        triggerVcnRequestListeners(requestListener);
+        mTestLooper.dispatchAll();
+        assertEquals(2, mVcn.getVcnGatewayConnections().size());
+        verify(mDeps, times(gatewayConnections.size() + 1))
+                .newVcnGatewayConnection(
+                        eq(mVcnContext),
+                        eq(TEST_SUB_GROUP),
+                        eq(mSubscriptionSnapshot),
+                        any(),
+                        mGatewayStatusCallbackCaptor.capture());
+    }
 }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index b760958..13e090d 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -2263,6 +2263,16 @@
     return 1;
   }
 
+  if (shared_lib_ && options_.private_symbols) {
+    // If a shared library styleable in a public R.java uses a private attribute, attempting to
+    // reference the private attribute within the styleable array will cause a link error because
+    // the private attribute will not be emitted in the public R.java.
+    context.GetDiagnostics()->Error(DiagMessage()
+                                    << "--shared-lib cannot currently be used in combination with"
+                                    << " --private-symbols");
+    return 1;
+  }
+
   if (options_.merge_only && !static_lib_) {
     context.GetDiagnostics()->Error(
         DiagMessage() << "the --merge-only flag can be only used when building a static library");
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 062dd8e..73072a9 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-#include "AppInfo.h"
 #include "Link.h"
 
+#include <android-base/file.h>
+
+#include "AppInfo.h"
 #include "LoadedApk.h"
 #include "test/Test.h"
 
 using testing::Eq;
+using testing::HasSubstr;
 using testing::Ne;
 
 namespace aapt {
@@ -317,4 +320,76 @@
   ASSERT_TRUE(Link(link_args, feature2_files_dir, &diag));
 }
 
+TEST_F(LinkTest, SharedLibraryAttributeRJava) {
+  StdErrDiagnostics diag;
+  const std::string lib_values =
+      R"(<resources>
+           <attr name="foo"/>
+           <public type="attr" name="foo" id="0x00010001"/>
+           <declare-styleable name="LibraryStyleable">
+             <attr name="foo" />
+           </declare-styleable>
+         </resources>)";
+
+  const std::string client_values =
+      R"(<resources>
+           <attr name="bar" />
+           <declare-styleable name="ClientStyleable">
+             <attr name="com.example.lib:foo" />
+             <attr name="bar" />
+           </declare-styleable>
+         </resources>)";
+
+  // Build a library with a public attribute
+  const std::string lib_res = GetTestPath("library-res");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), lib_values, lib_res, &diag));
+
+  const std::string lib_apk = GetTestPath("library.apk");
+  const std::string lib_java = GetTestPath("library_java");
+  // clang-format off
+  auto lib_manifest = ManifestBuilder(this)
+      .SetPackageName("com.example.lib")
+      .Build();
+
+  auto lib_link_args = LinkCommandBuilder(this)
+      .SetManifestFile(lib_manifest)
+      .AddFlag("--shared-lib")
+      .AddParameter("--java", lib_java)
+      .AddCompiledResDir(lib_res, &diag)
+      .Build(lib_apk);
+  // clang-format on
+  ASSERT_TRUE(Link(lib_link_args, &diag));
+
+  const std::string lib_r_java = lib_java + "/com/example/lib/R.java";
+  std::string lib_r_contents;
+  ASSERT_TRUE(android::base::ReadFileToString(lib_r_java, &lib_r_contents));
+  EXPECT_THAT(lib_r_contents, HasSubstr(" public static int foo=0x00010001;"));
+  EXPECT_THAT(lib_r_contents, HasSubstr(" com.example.lib.R.attr.foo"));
+
+  // Build a client that uses the library attribute in a declare-styleable
+  const std::string client_res = GetTestPath("client-res");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), client_values, client_res, &diag));
+
+  const std::string client_apk = GetTestPath("client.apk");
+  const std::string client_java = GetTestPath("client_java");
+  // clang-format off
+  auto client_manifest = ManifestBuilder(this)
+      .SetPackageName("com.example.client")
+      .Build();
+
+  auto client_link_args = LinkCommandBuilder(this)
+      .SetManifestFile(client_manifest)
+      .AddParameter("--java", client_java)
+      .AddParameter("-I", lib_apk)
+      .AddCompiledResDir(client_res, &diag)
+      .Build(client_apk);
+  // clang-format on
+  ASSERT_TRUE(Link(client_link_args, &diag));
+
+  const std::string client_r_java = client_java + "/com/example/client/R.java";
+  std::string client_r_contents;
+  ASSERT_TRUE(android::base::ReadFileToString(client_r_java, &client_r_contents));
+  EXPECT_THAT(client_r_contents, HasSubstr(" com.example.lib.R.attr.foo, 0x7f010000"));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index eb0ade6..4b90b4f 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -570,7 +570,6 @@
       ResourceEntry* entry = sorted_entries->at(entryIndex);
 
       // Populate the config masks for this entry.
-
       if (entry->visibility.level == Visibility::Level::kPublic) {
         config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
       }
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 1e4b681..995495a 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -70,8 +70,8 @@
     return name_;
   }
 
-  void Print(bool final, text::Printer* printer, bool strip_api_annotations = false)
-      const override {
+  void Print(bool final, text::Printer* printer,
+             bool strip_api_annotations = false) const override {
     using std::to_string;
 
     ClassMember::Print(final, printer, strip_api_annotations);
@@ -127,13 +127,13 @@
 using ResourceMember = PrimitiveMember<ResourceId>;
 using StringMember = PrimitiveMember<std::string>;
 
-template <typename T>
+template <typename T, typename StringConverter>
 class PrimitiveArrayMember : public ClassMember {
  public:
   explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
 
   void AddElement(const T& val) {
-    elements_.push_back(val);
+    elements_.emplace_back(val);
   }
 
   bool empty() const override {
@@ -158,7 +158,7 @@
         printer->Println();
       }
 
-      printer->Print(to_string(*current));
+      printer->Print(StringConverter::ToString(*current));
       if (std::distance(current, end) > 1) {
         printer->Print(", ");
       }
@@ -175,7 +175,24 @@
   std::vector<T> elements_;
 };
 
-using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
+struct FieldReference {
+  explicit FieldReference(std::string reference) : ref(std::move(reference)) {
+  }
+  std::string ref;
+};
+
+struct ResourceArrayMemberStringConverter {
+  static std::string ToString(const std::variant<ResourceId, FieldReference>& ref) {
+    if (auto id = std::get_if<ResourceId>(&ref)) {
+      return to_string(*id);
+    } else {
+      return std::get<FieldReference>(ref).ref;
+    }
+  }
+};
+
+using ResourceArrayMember = PrimitiveArrayMember<std::variant<ResourceId, FieldReference>,
+                                                 ResourceArrayMemberStringConverter>;
 
 // Represents a method in a class.
 class MethodDefinition : public ClassMember {
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index f0f839d..59dd481 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -224,7 +224,16 @@
   return cmp_ids_dynamic_after_framework(lhs_id, rhs_id);
 }
 
-void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
+static FieldReference GetRFieldReference(const ResourceName& name,
+                                         StringPiece fallback_package_name) {
+  const std::string package_name =
+      name.package.empty() ? fallback_package_name.to_string() : name.package;
+  const std::string entry = JavaClassGenerator::TransformToFieldName(name.entry);
+  return FieldReference(
+      StringPrintf("%s.R.%s.%s", package_name.c_str(), to_string(name.type).data(), entry.c_str()));
+}
+
+bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
                                           const Styleable& styleable,
                                           const StringPiece& package_name_to_generate,
                                           ClassDefinition* out_class_def,
@@ -340,14 +349,29 @@
 
   // Add the ResourceIds to the array member.
   for (size_t i = 0; i < attr_count; i++) {
-    const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0));
-    array_def->AddElement(id);
+    const StyleableAttr& attr = sorted_attributes[i];
+    std::string r_txt_contents;
+    if (attr.symbol && attr.symbol.value().is_dynamic) {
+      if (!attr.attr_ref->name) {
+        error_ = "unable to determine R.java field name of dynamic resource";
+        return false;
+      }
+
+      const FieldReference field_name =
+          GetRFieldReference(attr.attr_ref->name.value(), package_name_to_generate);
+      array_def->AddElement(field_name);
+      r_txt_contents = field_name.ref;
+    } else {
+      const ResourceId attr_id = attr.attr_ref->id.value_or_default(ResourceId(0));
+      array_def->AddElement(attr_id);
+      r_txt_contents = to_string(attr_id);
+    }
 
     if (r_txt_printer != nullptr) {
       if (i != 0) {
         r_txt_printer->Print(",");
       }
-      r_txt_printer->Print(" ").Print(id.to_string());
+      r_txt_printer->Print(" ").Print(r_txt_contents);
     }
   }
 
@@ -419,19 +443,7 @@
     }
   }
 
-  // If there is a rewrite method to generate, add the statements that rewrite package IDs
-  // for this styleable.
-  if (out_rewrite_method != nullptr) {
-    out_rewrite_method->AppendStatement(
-        StringPrintf("for (int i = 0; i < styleable.%s.length; i++) {", array_field_name.data()));
-    out_rewrite_method->AppendStatement(
-        StringPrintf("  if ((styleable.%s[i] & 0xff000000) == 0) {", array_field_name.data()));
-    out_rewrite_method->AppendStatement(
-        StringPrintf("    styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | packageIdBits;",
-                     array_field_name.data(), array_field_name.data()));
-    out_rewrite_method->AppendStatement("  }");
-    out_rewrite_method->AppendStatement("}");
-  }
+  return true;
 }
 
 void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id,
@@ -448,8 +460,7 @@
 
   const std::string field_name = TransformToFieldName(name.entry);
   if (out_class_def != nullptr) {
-    std::unique_ptr<ResourceMember> resource_member =
-        util::make_unique<ResourceMember>(field_name, real_id);
+    auto resource_member = util::make_unique<ResourceMember>(field_name, real_id);
 
     // Build the comments and annotations for this entry.
     AnnotationProcessor* processor = resource_member->GetCommentBuilder();
@@ -551,12 +562,11 @@
 
     if (resource_name.type == ResourceType::kStyleable) {
       CHECK(!entry->values.empty());
-
-      const Styleable* styleable =
-          static_cast<const Styleable*>(entry->values.front()->value.get());
-
-      ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def,
-                       out_rewrite_method_def, r_txt_printer);
+      const auto styleable = reinterpret_cast<const Styleable*>(entry->values.front()->value.get());
+      if (!ProcessStyleable(resource_name, id, *styleable, package_name_to_generate,
+                            out_type_class_def, out_rewrite_method_def, r_txt_printer)) {
+        return false;
+      }
     } else {
       ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def,
                       r_txt_printer);
@@ -626,8 +636,7 @@
 
       if (type->type == ResourceType::kAttr) {
         // Also include private attributes in this same class.
-        const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate);
-        if (priv_type) {
+        if (const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate)) {
           if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
                            rewrite_method.get(), r_txt_printer.get())) {
             return false;
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 853120b..d9d1b39 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -105,7 +105,7 @@
   // Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for
   // its package ID if `out_rewrite_method` is not nullptr.
   // `package_name_to_generate` is the package
-  void ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
+  bool ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
                         const Styleable& styleable,
                         const android::StringPiece& package_name_to_generate,
                         ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 04e2010..ec5b415 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -581,7 +581,7 @@
   out.Flush();
 
   EXPECT_THAT(output, HasSubstr("public static final int[] MyStyleable={"));
-  EXPECT_THAT(output, HasSubstr("0x01010000, 0x00010000"));
+  EXPECT_THAT(output, HasSubstr("0x01010000, lib.R.attr.dynamic_attr"));
   EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_android_framework_attr=0;"));
   EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_dynamic_attr=1;"));
 }
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index daedc2a..98ee63d 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -370,11 +370,11 @@
   } else {
     s = util::make_unique<SymbolTable::Symbol>();
     s->id = res_id;
-    s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id(), real_name.package);
   }
 
   if (s) {
     s->is_public = (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+    s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id(), real_name.package);
     return s;
   }
   return {};
@@ -417,11 +417,11 @@
   } else {
     s = util::make_unique<SymbolTable::Symbol>();
     s->id = id;
-    s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id(), name.package);
   }
 
   if (s) {
     s->is_public = (*flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+    s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id(), name.package);
     return s;
   }
   return {};
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index 5386802..f94f0fe 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -18,18 +18,17 @@
 
 #include <dirent.h>
 
-#include "android-base/errors.h"
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-#include "android-base/utf8.h"
-#include "androidfw/StringPiece.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
+#include <android-base/errors.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/utf8.h>
+#include <androidfw/StringPiece.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
 #include "cmd/Compile.h"
 #include "cmd/Link.h"
 #include "io/FileStream.h"
-#include "io/Util.h"
 #include "util/Files.h"
 
 using testing::Eq;
@@ -170,4 +169,74 @@
   }
 }
 
+ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
+}
+
+ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) {
+  package_name_ = package_name;
+  return *this;
+}
+
+ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) {
+  contents_ += contents + "\n";
+  return *this;
+}
+
+std::string ManifestBuilder::Build(const std::string& file_path) {
+  const char* manifest_template = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="%s">
+          %s
+      </manifest>)";
+
+  fixture_->WriteFile(file_path, android::base::StringPrintf(
+                                     manifest_template, package_name_.c_str(), contents_.c_str()));
+  return file_path;
+}
+
+std::string ManifestBuilder::Build() {
+  return Build(fixture_->GetTestPath("AndroidManifest.xml"));
+}
+
+LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
+}
+
+LinkCommandBuilder& LinkCommandBuilder::SetManifestFile(const std::string& file) {
+  manifest_supplied_ = true;
+  args_.emplace_back("--manifest");
+  args_.emplace_back(file);
+  return *this;
+}
+
+LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) {
+  args_.emplace_back(flag);
+  return *this;
+}
+
+LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir,
+                                                          IDiagnostics* diag) {
+  if (auto files = file::FindFiles(dir, diag)) {
+    for (std::string& compile_file : files.value()) {
+      args_.emplace_back(file::BuildPath({dir, compile_file}));
+    }
+  }
+  return *this;
+}
+
+LinkCommandBuilder& LinkCommandBuilder::AddParameter(const std::string& param,
+                                                     const std::string& value) {
+  args_.emplace_back(param);
+  args_.emplace_back(value);
+  return *this;
+}
+
+std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) {
+  if (!manifest_supplied_) {
+    SetManifestFile(ManifestBuilder(fixture_).Build());
+  }
+  args_.emplace_back("-o");
+  args_.emplace_back(out_apk);
+  return args_;
+}
+
 } // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index 457d65e..f8c4889 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -32,7 +32,7 @@
 class TestDirectoryFixture : public ::testing::Test {
  public:
   TestDirectoryFixture() = default;
-  virtual ~TestDirectoryFixture() = default;
+  ~TestDirectoryFixture() override = default;
 
   // Creates the test directory or clears its contents if it contains previously created files.
   void SetUp() override;
@@ -41,14 +41,14 @@
   void TearDown() override;
 
   // Retrieve the test directory of the fixture.
-  const android::StringPiece GetTestDirectory() {
+  android::StringPiece GetTestDirectory() {
     return temp_dir_;
   }
 
   // Retrieves the absolute path of the specified relative path in the test directory. Directories
   // should be separated using forward slashes ('/'), and these slashes will be translated to
   // backslashes when running Windows tests.
-  const std::string GetTestPath(const android::StringPiece& path) {
+  std::string GetTestPath(const android::StringPiece& path) {
     std::string base = temp_dir_;
     for (android::StringPiece part : util::Split(path, '/')) {
       file::AppendPath(&base, part);
@@ -68,7 +68,7 @@
 class CommandTestFixture : public TestDirectoryFixture {
  public:
   CommandTestFixture() = default;
-  virtual ~CommandTestFixture() = default;
+  ~CommandTestFixture() override = default;
 
   // Wries the contents of the file to the specified path. The file is compiled and the flattened
   // file is written to the out directory.
@@ -99,6 +99,33 @@
   DISALLOW_COPY_AND_ASSIGN(CommandTestFixture);
 };
 
+struct ManifestBuilder {
+  explicit ManifestBuilder(CommandTestFixture* fixture);
+  ManifestBuilder& AddContents(const std::string& contents);
+  ManifestBuilder& SetPackageName(const std::string& package_name);
+  std::string Build(const std::string& file_path);
+  std::string Build();
+
+ private:
+  CommandTestFixture* fixture_;
+  std::string package_name_ = CommandTestFixture::kDefaultPackageName;
+  std::string contents_;
+};
+
+struct LinkCommandBuilder {
+  explicit LinkCommandBuilder(CommandTestFixture* fixture);
+  LinkCommandBuilder& AddCompiledResDir(const std::string& dir, IDiagnostics* diag);
+  LinkCommandBuilder& AddFlag(const std::string& flag);
+  LinkCommandBuilder& AddParameter(const std::string& param, const std::string& value);
+  LinkCommandBuilder& SetManifestFile(const std::string& manifest_path);
+  std::vector<std::string> Build(const std::string& out_apk_path);
+
+ private:
+  CommandTestFixture* fixture_;
+  std::vector<std::string> args_;
+  bool manifest_supplied_ = false;
+};
+
 } // namespace aapt
 
 #endif  // AAPT_TEST_FIXTURE_H
\ No newline at end of file
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index df64a80..2a88732 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -89,8 +89,8 @@
     }
 
     Json::Value json;
-    Json::Reader reader;
-    if (!reader.parse(stream, json)) {
+    Json::CharReaderBuilder builder;
+    if (!Json::parseFromStream(builder, stream, &json, /* errorMessage = */ nullptr)) {
         return;
     }
 
@@ -132,8 +132,9 @@
         return;
     }
 
-    Json::StyledStreamWriter writer("  ");
-
+    Json::StreamWriterBuilder factory;
+    factory["indentation"] = "  ";
+    std::unique_ptr<Json::StreamWriter> const writer(factory.newStreamWriter());
     Json::Value json(Json::objectValue);
 
     for (map<string,string>::const_iterator it = m_cache.begin(); it != m_cache.end(); it++) {
@@ -141,7 +142,7 @@
     }
 
     std::ofstream stream(m_filename, std::ofstream::binary);
-    writer.write(stream, json);
+    writer->write(json, &stream);
 }
 
 string
@@ -212,8 +213,8 @@
     }
 
     Json::Value json;
-    Json::Reader reader;
-    if (!reader.parse(stream, json)) {
+    Json::CharReaderBuilder builder;
+    if (!Json::parseFromStream(builder, stream, &json, /* errorMessage = */ nullptr)) {
         json_error(filename, "can't parse json format", quiet);
         return;
     }
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index ebc0ec1..e775e1a 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -11,12 +11,6 @@
 
 EMOJI_VS = 0xFE0F
 
-#TODO(179952916): Rename CutiveMono and DancingScript
-CANONICAL_NAME_EXCEPTION_LIST = [
-    'CutiveMono.ttf',
-    'DancingScript-Regular.ttf',
-]
-
 LANG_TO_SCRIPT = {
     'as': 'Beng',
     'be': 'Cyrl',
@@ -703,8 +697,6 @@
 def check_canonical_name():
   for record in _all_fonts:
     file_name, index = record.font
-    if file_name in CANONICAL_NAME_EXCEPTION_LIST:
-      continue
 
     if index and index != 0:
       continue